Skip to main content

antlr4_runtime/
parser.rs

1// SPDX-License-Identifier: BSD-3-Clause
2// Copyright (c) 2026 Konstantin Vyatkin
3// `HashMap`/`HashSet` here are used as parser-internal caches keyed on
4// stable ATN coordinates (state numbers, token indices). They're never
5// iterated externally, so the project's `disallowed_types` lint (which
6// guards against non-deterministic iteration order leaking out) does not
7// apply to these uses.
8use std::cell::RefCell;
9use std::cmp::Ordering;
10#[allow(clippy::disallowed_types)]
11use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
12use std::hash::{BuildHasherDefault, Hash, Hasher};
13use std::rc::Rc;
14
15/// Rotate constant copied from rustc-hash / `FxHash`. The default
16/// `RandomState` hasher seeds itself from the OS RNG and runs `SipHash` on
17/// every key, which dominates `recognize_state_fast`'s memo lookups;
18/// `FxHasher` is a streaming integer hasher with near-zero per-call overhead
19/// and matches the access pattern of small integer keys that the parser memo
20/// uses.
21#[derive(Clone, Copy, Default)]
22struct FxHasher {
23    hash: u64,
24}
25
26const FX_ROT: u32 = 5;
27const FX_SEED: u64 = 0x51_7c_c1_b7_27_22_0a_95;
28
29impl Hasher for FxHasher {
30    /// Folds bytes 8 at a time so a `write(&[u8; 8])` call hashes to the same
31    /// state as a `write_u64` of the same little-endian bits. The `Hash` impls
32    /// for `String`, `[u8; N]`, and slice-like types reach the hasher through
33    /// `write`; matching the typed-method behaviour avoids the silent
34    /// divergence flagged in PR #5 review (Greptile P2). Tail bytes that do
35    /// not form a full word are mixed one at a time with the same constants,
36    /// keeping behaviour deterministic regardless of the slice length.
37    #[inline]
38    fn write(&mut self, mut bytes: &[u8]) {
39        while bytes.len() >= 8 {
40            let (head, rest) = bytes.split_at(8);
41            let word = u64::from_le_bytes(head.try_into().expect("8-byte chunk"));
42            self.hash = (self.hash.rotate_left(FX_ROT) ^ word).wrapping_mul(FX_SEED);
43            bytes = rest;
44        }
45        for byte in bytes {
46            self.hash = (self.hash.rotate_left(FX_ROT) ^ u64::from(*byte)).wrapping_mul(FX_SEED);
47        }
48    }
49    #[inline]
50    fn write_u64(&mut self, value: u64) {
51        self.hash = (self.hash.rotate_left(FX_ROT) ^ value).wrapping_mul(FX_SEED);
52    }
53    #[inline]
54    fn write_usize(&mut self, value: usize) {
55        self.write_u64(value as u64);
56    }
57    #[inline]
58    fn write_u32(&mut self, value: u32) {
59        self.write_u64(u64::from(value));
60    }
61    #[inline]
62    fn write_i32(&mut self, value: i32) {
63        self.write_u64(u64::from(i32::cast_unsigned(value)));
64    }
65    #[inline]
66    fn finish(&self) -> u64 {
67        self.hash
68    }
69}
70
71type FxBuildHasher = BuildHasherDefault<FxHasher>;
72#[allow(clippy::disallowed_types)]
73type FxHashMap<K, V> = HashMap<K, V, FxBuildHasher>;
74#[allow(clippy::disallowed_types)]
75type FxHashSet<K> = HashSet<K, FxBuildHasher>;
76
77use crate::atn::AtnStateKind;
78use crate::atn::parser::{
79    ParserAtnPrediction, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
80    ParserAtnSimulatorError, ParserSemanticCandidate,
81};
82use crate::atn::parser_atn::{
83    ParserAtn as Atn, ParserAtnState as AtnState, ParserIntervalSet, ParserTransition,
84    ParserTransitionData as Transition, ParserTransitionKind,
85};
86#[cfg(test)]
87use crate::atn::parser_atn::{ParserAtnBuilder, ParserTransitionSpec};
88use crate::char_stream::CharStream;
89use crate::errors::{AntlrError, SyntaxErrorEvent};
90use crate::int_stream::IntStream;
91use crate::lexer::{LexerCustomAction, LexerLifecycleCtx, LexerSemCtx};
92use crate::prediction::SemanticContext;
93use crate::recognizer::{Recognizer, RecognizerData};
94use crate::semir::{self, AStmt, ArithOp, CmpOp, ExprId, HookId, MemberEnv, PExpr, SemIr, StmtId};
95use crate::token::{
96    TOKEN_EOF, Token, TokenId, TokenSource, TokenSourceError, TokenSpec, TokenStore, TokenView,
97};
98use crate::token_stream::CommonTokenStream;
99use crate::tree::{
100    Node, NodeId, ParseTreeCheckpoint, ParseTreeStorage, ParsedFile, ParserRuleContext,
101};
102use crate::vocabulary::Vocabulary;
103
104type ParseTree = NodeId;
105
106/// Upper bound for the recursive metadata recognizer before it treats a path as
107/// non-viable. Long expression-regression descriptors legitimately walk tens
108/// of thousands of ATN edges.
109const RECOGNITION_DEPTH_LIMIT: usize = 32_768;
110/// Preserve the recursive hot path while checking native stack capacity often
111/// enough that one unchecked group cannot cross the protected red zone.
112const FAST_RECOGNIZE_STACK_CHECK_INTERVAL: usize = 8;
113const FAST_RECOGNIZE_RED_ZONE: usize = 1024 * 1024;
114const FAST_RECOGNIZE_STACK_SIZE: usize = 4 * 1024 * 1024;
115/// Generated recursive-descent rule methods map grammar-rule nesting onto
116/// native call depth. Their dispatch boundary samples remaining stack capacity
117/// once per this many rule-context frames, so between two samples at most this
118/// many rule bodies of native growth can occur — far below the red zone.
119const GENERATED_RULE_STACK_CHECK_INTERVAL: usize = 8;
120/// Whole-rule direct adaptive execution is allowed to give up and fall back to
121/// the existing recognizer. Keep the guard at the same order of magnitude as
122/// speculative recognition so malformed cyclic ATNs cannot spin forever.
123const ADAPTIVE_DIRECT_STEP_LIMIT: usize = RECOGNITION_DEPTH_LIMIT;
124
125/// Runs a generated rule body after ensuring native stack capacity, growing
126/// onto a segmented stack when remaining capacity enters the red zone.
127///
128/// Generated rule dispatch calls this when
129/// [`BaseParser::generated_rule_stack_check_due`] fires so deeply nested input
130/// parses (or reports a syntax error) instead of aborting the process.
131pub fn grow_generated_rule_stack<R>(body: impl FnOnce() -> R) -> R {
132    stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, body)
133}
134
135/// Shared lifecycle and recovery shell for generated parser rules.
136///
137/// This is an implementation detail of `antlr4-rust-gen`, not a stable
138/// hand-written parser API. The binders supplied by generated code keep
139/// grammar-specific locals and steps inline while this macro owns the entry,
140/// recovery, and exit state machine.
141#[doc(hidden)]
142#[macro_export]
143macro_rules! __antlr4_rust_generated_rule {
144    (
145        ordinary $parser:ident, $state:expr, $rule:expr, $allow_fallback:expr,
146        $atn:expr, $fatal:path;
147        retry [$($retry:tt)*];
148        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
149        setup { $($setup:tt)* }
150        body { $($body:tt)* }
151        success { $($success:tt)* }
152        recovery { $($recovery:tt)* }
153    ) => {
154        $crate::__antlr4_rust_generated_rule! {
155            @body
156            parser $parser;
157            enter $parser.base.enter_rule($state, $rule);
158            finish finish_rule;
159            abort exit_rule;
160            allow_fallback $allow_fallback;
161            atn $atn;
162            fatal $fatal;
163            retry [$($retry)*];
164            bind ($ctx, $rule_start, $consumed_eof, $sync_error);
165            setup { $($setup)* }
166            body { $($body)* }
167            success { $($success)* }
168            recovery { $($recovery)* }
169        }
170    };
171    (
172        recursive $parser:ident, $state:expr, $rule:expr, $precedence:expr,
173        $allow_fallback:expr, $atn:expr, $fatal:path;
174        retry [$($retry:tt)*];
175        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
176        setup { $($setup:tt)* }
177        body { $($body:tt)* }
178        success { $($success:tt)* }
179        recovery { $($recovery:tt)* }
180    ) => {
181        $crate::__antlr4_rust_generated_rule! {
182            @body
183            parser $parser;
184            enter $parser.base.enter_recursion_rule($state, $rule, $precedence);
185            finish finish_recursion_rule;
186            abort unroll_recursion_context;
187            allow_fallback $allow_fallback;
188            atn $atn;
189            fatal $fatal;
190            retry [$($retry)*];
191            bind ($ctx, $rule_start, $consumed_eof, $sync_error);
192            setup { $($setup)* }
193            body { $($body)* }
194            success { $($success)* }
195            recovery { $($recovery)* }
196        }
197    };
198    (
199        @body
200        parser $parser:ident;
201        enter $enter:expr;
202        finish $finish:ident;
203        abort $abort:ident;
204        allow_fallback $allow_fallback:expr;
205        atn $atn:expr;
206        fatal $fatal:path;
207        retry [$($retry:tt)*];
208        bind ($ctx:ident, $rule_start:ident, $consumed_eof:ident, $sync_error:ident);
209        setup { $($setup:tt)* }
210        body { $($body:tt)* }
211        success { $($success:tt)* }
212        recovery { $($recovery:tt)* }
213    ) => {{
214        let __generated_diagnostic_marker =
215            $parser.base.generated_diagnostics_checkpoint();
216        let mut $ctx = $enter;
217        let $rule_start = $crate::IntStream::index($parser.base.input());
218        $($setup)*
219        let mut $consumed_eof = false;
220        let mut $sync_error: Option<$crate::AntlrError> = None;
221        // The body has its own Result boundary: `?` and `return` exit only this
222        // closure, with errors entering recovery. Parser borrows must not escape it.
223        let __result = (|| -> Result<(), $crate::AntlrError> {
224            $($body)*
225            Ok(())
226        })();
227        match __result {
228            Ok(()) => {
229                $($success)*
230                let __tree = $parser.base.$finish($ctx, $consumed_eof);
231                Ok(__tree)
232            }
233            Err(__error) => {
234                $crate::__antlr4_rust_generated_rule! {
235                    @retry
236                    [$($retry)*]
237                    parser $parser;
238                    marker __generated_diagnostic_marker;
239                    abort $abort;
240                }
241                let __error = if let Some(__sync_error) = $sync_error {
242                    if $allow_fallback {
243                        $parser.base.$abort();
244                        $parser
245                            .base
246                            .rollback_generated_tree(__generated_diagnostic_marker);
247                        $parser.base.record_generated_syntax_error();
248                        return Err($fatal(__sync_error));
249                    }
250                    __sync_error
251                } else {
252                    __error
253                };
254                $parser
255                    .base
256                    .recover_generated_rule(&mut $ctx, $atn, __error);
257                $($recovery)*
258                let __tree = $parser.base.$finish($ctx, $consumed_eof);
259                Ok(__tree)
260            }
261        }
262    }};
263    (
264        @retry
265        [none]
266        parser $parser:ident;
267        marker $marker:ident;
268        abort $abort:ident;
269    ) => {};
270    (
271        @retry
272        [adaptive]
273        parser $parser:ident;
274        marker $marker:ident;
275        abort $abort:ident;
276    ) => {
277        // Uniform adaptive-ATN retry unwind against the generated parser's
278        // fixed `adaptive_atn` state; `retry_pending()` constant-folds to
279        // `false` for grammars without adaptive retry slots.
280        if $parser.adaptive_atn.retry_pending() {
281            $parser.base.$abort();
282            $parser.base.restore_generated_diagnostics($marker);
283            return Err($crate::generated::GeneratedRuleError::AdaptiveRetry);
284        }
285    };
286}
287
288/// Pushes invoking state, evaluates a subrule call, discards the marker on
289/// both success and error paths, propagates the error, and appends the child.
290///
291/// Replaces the 5-line generated motif:
292/// ```ignore
293/// let __invoking_marker = self.base.push_invoking_state(STATE);
294/// let __child = CALL;
295/// self.base.discard_invoking_state(__invoking_marker);
296/// let __child = __child?;
297/// self.base.add_parse_child(&mut __ctx, __child);
298/// ```
299///
300/// The macro is necessary because the child call borrows `self` (the generated
301/// parser), which contains `base`, so the push/discard cannot be a single
302/// method call on `BaseParser`.
303#[macro_export]
304#[doc(hidden)]
305macro_rules! __antlr4_rust_invoke_subrule {
306    ($parser:ident, $state:expr, $call:expr, $ctx:ident) => {{
307        let __invoking_marker = $parser.base.push_invoking_state($state);
308        let __child = $call;
309        $parser.base.discard_invoking_state(__invoking_marker);
310        let __child = __child?;
311        $parser.base.add_parse_child(&mut $ctx, __child);
312    }};
313}
314
315/// Receives committed rule enter/exit events during recognition, matching
316/// ANTLR's `addParseListener` contract ([`Parser::add_parse_listener`],
317/// also inherent on [`BaseParser`] and generated parsers).
318///
319/// Events fire on the generated recursive-descent path as rules are entered
320/// and exited, with left-recursive operator loops following upstream's
321/// timing exactly: each loop pass first exits the outgoing iteration
322/// (`recRuleSetPrevCtx`) and then enters the new expansion
323/// (`pushNewRecursionContext` firing `triggerEnterRuleEvent`), so live
324/// listener depth never accumulates across a flat operator chain —
325/// `a + a + … + a` peaks at depth 2 like every ANTLR target. On expansion
326/// events, [`EnterRuleEvent::current`] anchors at the operator-side
327/// lookahead (the token the expansion starts at), whereas Java's
328/// `ctx.start` reaches back to the whole expression's first token — anchor
329/// diagnostics accordingly. Enter events fire in registration order and
330/// exit events in reverse registration order, matching upstream. Enter/exit
331/// calls balance on every completed path, including error recovery and
332/// aborts inside operator loops — with one exception shared with Java: an
333/// ordinary rule's enter that returns `Err` receives no matching exit
334/// (upstream calls `enterRule` outside the generated `try`/`finally`, so a
335/// throwing listener skips `exitRule` the same way). Listener state shared
336/// across parses via `Arc` should be reset after an abort (the unmatched
337/// ordinary-rule enter leaves counters one high).
338///
339/// Divergence from Java to know about: upstream generated rule methods run
340/// only on the committed parse, while this runtime may re-enter a rule while
341/// recovering from a syntax error — such retries deliver additional balanced
342/// enter/exit pairs. Depth counters and resource bounds (the primary use
343/// case) are unaffected; exact once-per-node collectors should prefer the
344/// post-parse tree walker.
345///
346/// `enter_every_rule` is fallible: returning `Err` aborts the parse with
347/// that error. The abort is sticky through rule-level recovery — the parse
348/// fails even when recovery could have produced a tree, mirroring how a
349/// thrown exception escapes ANTLR's `triggerEnterRuleEvent`. Rules the
350/// generator emitted no body for (interpreter-only fallback) do not fire
351/// events; when any parse listener is registered, generated dispatch routes
352/// ATN-preferred rules through their generated bodies so real grammars
353/// observe every rule.
354///
355/// Cost: with no listener registered, dispatch pays one emptiness check per
356/// rule boundary (benchmarked at baseline). With one registered, dispatch
357/// itself is a few percent; on grammars where the generator classified rules
358/// ATN-preferred, the dominant cost is the routing override above — the same
359/// one [`Parser::set_max_rule_depth`] takes — which trades that fast path
360/// for observability. Grammars without ATN-preferred rules (most small DSLs)
361/// pay only the dispatch.
362pub trait ParseListener: Send {
363    /// Called when a generated rule is entered, before its body runs, and
364    /// once per left-recursive operator expansion.
365    ///
366    /// Returning `Err` aborts the parse with the given error.
367    fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError>;
368
369    /// Called when a generated rule exits, after its body (and any rule-level
370    /// error recovery) finished, and once per left-recursive operator
371    /// expansion as the rule unrolls.
372    fn exit_every_rule(&mut self, rule_index: usize) {
373        let _ = rule_index;
374    }
375}
376
377/// Boxed listeners forward to their inner implementation, so the boxes
378/// returned by [`Parser::remove_parse_listeners`] can be re-registered
379/// through [`Parser::add_parse_listener`] unchanged.
380impl<T: ParseListener + ?Sized> ParseListener for Box<T> {
381    fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError> {
382        (**self).enter_every_rule(event)
383    }
384
385    fn exit_every_rule(&mut self, rule_index: usize) {
386        (**self).exit_every_rule(rule_index);
387    }
388}
389
390/// A rule-entry event delivered to [`ParseListener::enter_every_rule`].
391///
392/// Non-exhaustive so future fields (alt number, invoking state, a context
393/// handle) extend the event without breaking implementors.
394#[derive(Debug)]
395#[non_exhaustive]
396pub struct EnterRuleEvent<'a> {
397    /// Index of the rule being entered (compare against the generated
398    /// `RULE_*` constants).
399    pub rule_index: usize,
400    /// The lookahead token the rule starts at — its line/column/offsets
401    /// anchor listener diagnostics — or `None` at end of input.
402    pub current: Option<TokenView<'a>>,
403}
404
405struct ParseListenerSlot(Box<dyn ParseListener>);
406
407impl std::fmt::Debug for ParseListenerSlot {
408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409        f.write_str("ParseListener")
410    }
411}
412/// Probe window for deciding whether clean-pass memo entries are reusable
413/// enough to keep caching. High-cardinality parses mostly produce one-shot
414/// entries; compact ambiguous loops repeatedly hit the same keys.
415const CLEAN_MEMO_PROBE_LIMIT: usize = 4096;
416const CLEAN_MEMO_REPEAT_LIMIT: usize = 8;
417/// Sparse parses periodically reopen the bounded probe so a repeat-heavy
418/// region that starts later in the token stream can promote memoization.
419const CLEAN_MEMO_REPROBE_INTERVAL: usize = 262_144;
420const FAST_RECOGNIZE_VISITING_CAPACITY: usize = 256;
421const FAST_RECOGNIZE_MIN_MEMO_CAPACITY: usize = 256;
422const FAST_RECOGNIZE_MAX_MEMO_CAPACITY: usize = 524_288;
423const FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY: usize = 65_536;
424
425#[derive(Clone, Copy, Debug, Eq, PartialEq)]
426enum CleanMemoMode {
427    Probe,
428    Promote,
429    Sparse,
430}
431
432fn interval_set_contains(intervals: &[(i32, i32)], symbol: i32) -> bool {
433    intervals
434        .iter()
435        .any(|(start, stop)| (*start..=*stop).contains(&symbol))
436}
437
438fn interval_symbols(intervals: &[(i32, i32)]) -> BTreeSet<i32> {
439    let mut symbols = BTreeSet::new();
440    for (start, stop) in intervals {
441        symbols.extend(*start..=*stop);
442    }
443    symbols
444}
445
446fn interval_complement_symbols(
447    intervals: &[(i32, i32)],
448    min_vocabulary: i32,
449    max_vocabulary: i32,
450) -> BTreeSet<i32> {
451    (min_vocabulary..=max_vocabulary)
452        .filter(|symbol| !interval_set_contains(intervals, *symbol))
453        .collect()
454}
455
456#[cfg(feature = "perf-counters")]
457mod perf_counters {
458    use std::cell::Cell;
459    thread_local! {
460        pub(super) static RFS_CALLS: Cell<u64> = const { Cell::new(0) };
461        pub(super) static RFS_MEMO_HITS: Cell<u64> = const { Cell::new(0) };
462        pub(super) static RFS_MEMO_MISSES: Cell<u64> = const { Cell::new(0) };
463        pub(super) static RFS_VISITING_CYCLE: Cell<u64> = const { Cell::new(0) };
464        pub(super) static MEMO_INSERTED: Cell<u64> = const { Cell::new(0) };
465        pub(super) static OUTCOMES_PUSHED: Cell<u64> = const { Cell::new(0) };
466        pub(super) static OUTCOMES_CLONED: Cell<u64> = const { Cell::new(0) };
467        pub(super) static OUTCOME_DEDUPE_INPUTS: Cell<u64> = const { Cell::new(0) };
468        pub(super) static OUTCOME_DEDUPE_REMOVED: Cell<u64> = const { Cell::new(0) };
469        pub(super) static OUTCOME_DEDUPE_INLINE: Cell<u64> = const { Cell::new(0) };
470        pub(super) static OUTCOME_DEDUPE_DENSE: Cell<u64> = const { Cell::new(0) };
471        pub(super) static OUTCOME_DEDUPE_SPARSE: Cell<u64> = const { Cell::new(0) };
472        pub(super) static OUTCOME_DEDUPE_DENSE_WORDS: Cell<u64> = const { Cell::new(0) };
473    }
474    pub(super) fn inc(c: &'static std::thread::LocalKey<Cell<u64>>, n: u64) {
475        c.with(|v| v.set(v.get() + n));
476    }
477    thread_local! {
478        pub(super) static EPSILON_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
479        pub(super) static RULE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
480        pub(super) static ATOM_RANGE_TRANSITIONS: Cell<u64> = const { Cell::new(0) };
481        pub(super) static SINGLE_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
482        pub(super) static MULTI_TRANS_BODY: Cell<u64> = const { Cell::new(0) };
483        pub(super) static SINGLE_TRANS_RULE: Cell<u64> = const { Cell::new(0) };
484        pub(super) static SINGLE_TRANS_ATOM: Cell<u64> = const { Cell::new(0) };
485        pub(super) static SINGLE_TRANS_OTHER: Cell<u64> = const { Cell::new(0) };
486        pub(super) static OUTCOMES_RETURN_0: Cell<u64> = const { Cell::new(0) };
487        pub(super) static OUTCOMES_RETURN_1: Cell<u64> = const { Cell::new(0) };
488        pub(super) static OUTCOMES_RETURN_N: Cell<u64> = const { Cell::new(0) };
489    }
490    pub(super) fn snapshot() -> [(&'static str, u64); 24] {
491        [
492            ("rfs_calls", RFS_CALLS.with(Cell::get)),
493            ("rfs_memo_hits", RFS_MEMO_HITS.with(Cell::get)),
494            ("rfs_memo_misses", RFS_MEMO_MISSES.with(Cell::get)),
495            ("rfs_visiting_cycle", RFS_VISITING_CYCLE.with(Cell::get)),
496            ("memo_inserted", MEMO_INSERTED.with(Cell::get)),
497            ("outcomes_pushed", OUTCOMES_PUSHED.with(Cell::get)),
498            ("outcomes_cloned", OUTCOMES_CLONED.with(Cell::get)),
499            (
500                "outcome_dedupe_inputs",
501                OUTCOME_DEDUPE_INPUTS.with(Cell::get),
502            ),
503            (
504                "outcome_dedupe_removed",
505                OUTCOME_DEDUPE_REMOVED.with(Cell::get),
506            ),
507            (
508                "outcome_dedupe_inline",
509                OUTCOME_DEDUPE_INLINE.with(Cell::get),
510            ),
511            ("outcome_dedupe_dense", OUTCOME_DEDUPE_DENSE.with(Cell::get)),
512            (
513                "outcome_dedupe_sparse",
514                OUTCOME_DEDUPE_SPARSE.with(Cell::get),
515            ),
516            (
517                "outcome_dedupe_dense_words",
518                OUTCOME_DEDUPE_DENSE_WORDS.with(Cell::get),
519            ),
520            ("epsilon_transitions", EPSILON_TRANSITIONS.with(Cell::get)),
521            ("rule_transitions", RULE_TRANSITIONS.with(Cell::get)),
522            (
523                "atom_range_transitions",
524                ATOM_RANGE_TRANSITIONS.with(Cell::get),
525            ),
526            ("single_trans_body", SINGLE_TRANS_BODY.with(Cell::get)),
527            ("multi_trans_body", MULTI_TRANS_BODY.with(Cell::get)),
528            ("single_trans_rule", SINGLE_TRANS_RULE.with(Cell::get)),
529            ("single_trans_atom", SINGLE_TRANS_ATOM.with(Cell::get)),
530            ("single_trans_other", SINGLE_TRANS_OTHER.with(Cell::get)),
531            ("outcomes_return_0", OUTCOMES_RETURN_0.with(Cell::get)),
532            ("outcomes_return_1", OUTCOMES_RETURN_1.with(Cell::get)),
533            ("outcomes_return_n", OUTCOMES_RETURN_N.with(Cell::get)),
534        ]
535    }
536    pub fn reset() {
537        RFS_CALLS.with(|c| c.set(0));
538        RFS_MEMO_HITS.with(|c| c.set(0));
539        RFS_MEMO_MISSES.with(|c| c.set(0));
540        RFS_VISITING_CYCLE.with(|c| c.set(0));
541        MEMO_INSERTED.with(|c| c.set(0));
542        OUTCOMES_PUSHED.with(|c| c.set(0));
543        OUTCOMES_CLONED.with(|c| c.set(0));
544        OUTCOME_DEDUPE_INPUTS.with(|c| c.set(0));
545        OUTCOME_DEDUPE_REMOVED.with(|c| c.set(0));
546        OUTCOME_DEDUPE_INLINE.with(|c| c.set(0));
547        OUTCOME_DEDUPE_DENSE.with(|c| c.set(0));
548        OUTCOME_DEDUPE_SPARSE.with(|c| c.set(0));
549        OUTCOME_DEDUPE_DENSE_WORDS.with(|c| c.set(0));
550        EPSILON_TRANSITIONS.with(|c| c.set(0));
551        RULE_TRANSITIONS.with(|c| c.set(0));
552        ATOM_RANGE_TRANSITIONS.with(|c| c.set(0));
553        SINGLE_TRANS_BODY.with(|c| c.set(0));
554        MULTI_TRANS_BODY.with(|c| c.set(0));
555        SINGLE_TRANS_RULE.with(|c| c.set(0));
556        SINGLE_TRANS_ATOM.with(|c| c.set(0));
557        SINGLE_TRANS_OTHER.with(|c| c.set(0));
558        OUTCOMES_RETURN_0.with(|c| c.set(0));
559        OUTCOMES_RETURN_1.with(|c| c.set(0));
560        OUTCOMES_RETURN_N.with(|c| c.set(0));
561    }
562    pub fn dump() {
563        for (name, value) in snapshot() {
564            #[allow(clippy::print_stderr)]
565            {
566                eprintln!("perf {name}={value}");
567            }
568        }
569    }
570}
571
572#[cfg(feature = "perf-counters")]
573pub use perf_counters::{dump as dump_perf_counters, reset as reset_perf_counters};
574/// Preserve lazy lexing for short or failing inputs, but eagerly fill once the
575/// fast recognizer has probed far enough that per-token stream sync dominates.
576/// Sixty-four tokens is a small rule-sized window: it keeps startup lazy while
577/// switching long inputs to the cheaper filled-stream path before large fanout.
578const FAST_RECOGNIZER_DEFERRED_FILL_AT: usize = 64;
579/// Parser semantic action reached while recognizing one ATN path.
580///
581/// Generated parsers use `source_state` to dispatch back to the grammar action
582/// rendered for that ATN action transition. The token interval is the current
583/// rule's input span at the action site, which covers common target templates
584/// such as `$text`. Rule-init actions do not have an ATN action source state,
585/// so they are marked separately and may carry an ATN state for expected-token
586/// rendering.
587#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
588pub struct ParserAction {
589    source_state: usize,
590    rule_index: usize,
591    action_index: Option<usize>,
592    start_index: usize,
593    stop_index: Option<usize>,
594    rule_init: bool,
595    expected_state: Option<usize>,
596}
597
598impl ParserAction {
599    /// Creates an action event for a recognized parser path.
600    pub const fn new(
601        source_state: usize,
602        rule_index: usize,
603        start_index: usize,
604        stop_index: Option<usize>,
605    ) -> Self {
606        Self {
607            source_state,
608            rule_index,
609            action_index: None,
610            start_index,
611            stop_index,
612            rule_init: false,
613            expected_state: None,
614        }
615    }
616
617    /// Creates an indexed action event for a recognized parser path.
618    pub const fn new_indexed(
619        source_state: usize,
620        rule_index: usize,
621        action_index: usize,
622        start_index: usize,
623        stop_index: Option<usize>,
624    ) -> Self {
625        Self {
626            source_state,
627            rule_index,
628            action_index: Some(action_index),
629            start_index,
630            stop_index,
631            rule_init: false,
632            expected_state: None,
633        }
634    }
635
636    /// Creates an action event for a rule-level `@init` action.
637    pub const fn new_rule_init(
638        rule_index: usize,
639        start_index: usize,
640        expected_state: Option<usize>,
641    ) -> Self {
642        Self {
643            source_state: usize::MAX,
644            rule_index,
645            action_index: None,
646            start_index,
647            stop_index: None,
648            rule_init: true,
649            expected_state,
650        }
651    }
652
653    /// ATN state that owns the semantic-action transition.
654    pub const fn source_state(&self) -> usize {
655        self.source_state
656    }
657
658    /// Grammar rule index recorded by the serialized ATN action transition.
659    pub const fn rule_index(&self) -> usize {
660        self.rule_index
661    }
662
663    /// Stable source-order action index in the grammar.
664    pub const fn action_index(&self) -> Option<usize> {
665        self.action_index
666    }
667
668    /// Token-stream index where the active rule began.
669    pub const fn start_index(&self) -> usize {
670        self.start_index
671    }
672
673    /// Last token-stream index consumed before the action was reached.
674    pub const fn stop_index(&self) -> Option<usize> {
675        self.stop_index
676    }
677
678    /// Reports whether this event represents a rule-level `@init` action.
679    pub const fn is_rule_init(&self) -> bool {
680        self.rule_init
681    }
682
683    /// ATN state used to compute expected-token display for this action.
684    pub const fn expected_state(&self) -> Option<usize> {
685        self.expected_state
686    }
687}
688
689/// Runtime view passed to parser semantic hooks.
690///
691/// The context is intentionally read-only with respect to parser structure:
692/// predicates may run speculatively during prediction, and hooks can be called
693/// more than once for paths that are later abandoned. Lookahead methods may
694/// buffer tokens from the underlying token source, matching normal parser
695/// prediction behavior.
696pub struct ParserSemCtx<'a, S>
697where
698    S: TokenSource,
699{
700    input: &'a mut CommonTokenStream<S>,
701    tree_storage: &'a ParseTreeStorage,
702    rule_index: usize,
703    coordinate_index: usize,
704    rule_name: Option<String>,
705    context: Option<&'a ParserRuleContext>,
706    tree: Option<ParseTree>,
707    local_int_arg: Option<(usize, i64)>,
708    member_values: &'a MemberEnv,
709    action: Option<ParserAction>,
710}
711
712impl<S> std::fmt::Debug for ParserSemCtx<'_, S>
713where
714    S: TokenSource,
715{
716    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
717        f.debug_struct("ParserSemCtx")
718            .field("rule_index", &self.rule_index)
719            .field("coordinate_index", &self.coordinate_index)
720            .field("rule_name", &self.rule_name)
721            .field("context", &self.context)
722            .field("tree", &self.tree)
723            .field("local_int_arg", &self.local_int_arg)
724            .field("member_values", &self.member_values)
725            .field("action", &self.action)
726            .finish_non_exhaustive()
727    }
728}
729
730impl<'a, S> ParserSemCtx<'a, S>
731where
732    S: TokenSource,
733{
734    /// Rule index that owns the predicate/action coordinate.
735    #[must_use]
736    pub const fn rule_index(&self) -> usize {
737        self.rule_index
738    }
739
740    /// Rule name that owns the coordinate, when recognizer metadata has it.
741    #[must_use]
742    pub fn rule_name(&self) -> Option<&str> {
743        self.rule_name.as_deref()
744    }
745
746    /// Predicate/action index inside the owning rule. Legacy parser actions
747    /// without source-index metadata report `usize::MAX`.
748    #[must_use]
749    pub const fn coordinate_index(&self) -> usize {
750        self.coordinate_index
751    }
752
753    /// Current token-stream index.
754    #[must_use]
755    pub fn input_index(&self) -> usize {
756        self.input.index()
757    }
758
759    /// Token type at one-based lookahead/lookbehind offset.
760    pub fn la(&mut self, offset: isize) -> i32 {
761        self.input.la(offset)
762    }
763
764    /// Token at one-based lookahead/lookbehind offset.
765    pub fn lt(&self, offset: isize) -> Option<TokenView<'_>> {
766        self.input.lt(offset)
767    }
768
769    /// Borrowing token view for text inspection at a one-based offset.
770    pub fn token_text(&self, offset: isize) -> Option<TokenView<'_>> {
771        self.lt(offset)
772    }
773
774    /// Token at an absolute buffered index, including hidden/custom channels.
775    ///
776    /// Unlike [`Self::lt`], this does not apply the token stream's channel
777    /// filter and does not move its cursor. It is intended for semantic helpers
778    /// such as automatic-semicolon-insertion checks that inspect trivia
779    /// immediately before the current visible token.
780    pub fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
781        self.input.get(index)
782    }
783
784    /// Current generated rule context, when a generated rule predicate supplied
785    /// one.
786    #[must_use]
787    pub const fn context(&self) -> Option<&'a ParserRuleContext> {
788        self.context
789    }
790
791    /// Flat tree storage containing completed children visible to this hook.
792    #[must_use]
793    pub const fn parse_tree_storage(&self) -> &'a ParseTreeStorage {
794        self.tree_storage
795    }
796
797    /// Canonical token store used by completed flat-tree nodes.
798    #[must_use]
799    pub const fn token_store(&self) -> &TokenStore {
800        self.input.token_store()
801    }
802
803    /// Completed parse-tree root ID passed to a replayed action hook.
804    #[must_use]
805    pub const fn tree_id(&self) -> Option<NodeId> {
806        self.tree
807    }
808
809    /// Completed parse tree passed to an action hook, if the action is being
810    /// replayed after recognition.
811    #[must_use]
812    pub fn tree(&self) -> Option<Node<'_>> {
813        self.tree
814            .and_then(|id| self.tree_storage.node(self.input.token_store(), id))
815    }
816
817    /// Integer local argument visible to this predicate coordinate.
818    #[must_use]
819    pub fn local_int_arg(&self) -> Option<i64> {
820        self.local_int_arg.map(|(_, value)| value)
821    }
822
823    /// Integer member value observed on the current speculative path.
824    #[must_use]
825    pub fn member_int(&self, member: usize) -> Option<i64> {
826        self.member_values.scalar(member)
827    }
828
829    /// Top of a stack-valued member slot on the current speculative path;
830    /// `None` when the stack is empty or was never pushed.
831    #[must_use]
832    pub fn member_stack_top(&self, member: usize) -> Option<i64> {
833        self.member_values.stack_top(member)
834    }
835
836    /// Depth of a stack-valued member slot on the current speculative path.
837    #[must_use]
838    pub fn member_stack_len(&self, member: usize) -> usize {
839        self.member_values.stack_len(member)
840    }
841
842    /// Parser action event being replayed, when this context belongs to an
843    /// action hook.
844    #[must_use]
845    pub const fn action(&self) -> Option<ParserAction> {
846        self.action
847    }
848
849    /// Text covered by a parser action event.
850    ///
851    /// Mirrors [`BaseParser::text_interval`] / `$text`: when the stop token is
852    /// EOF the interval ends at the previous *visible* token, so trailing hidden
853    /// tokens (and the EOF marker) are excluded rather than blindly subtracting
854    /// one, which could point at hidden whitespace. `CommonTokenStream::text`
855    /// itself guards `start > stop`, so an empty interval yields `""`.
856    pub fn action_text(&self) -> String {
857        let Some(action) = self.action else {
858            return String::new();
859        };
860        let Some(stop) = action.stop_index() else {
861            return String::new();
862        };
863        let stop = if self
864            .input
865            .get(stop)
866            .is_some_and(|token| token.token_type() == TOKEN_EOF)
867        {
868            let Some(previous) = self.input.previous_visible_token_index(stop) else {
869                return String::new();
870            };
871            previous
872        } else {
873            stop
874        };
875        self.input.text(action.start_index(), stop)
876    }
877}
878
879/// User extension point for parser semantic predicates and actions that the
880/// metadata generator did not translate into built-in runtime metadata.
881///
882/// Returning `None`/`false` says "not handled", so the runtime falls through
883/// to the configured [`UnknownSemanticPolicy`]. Predicate hooks may run during
884/// speculative prediction and must be replay-safe.
885pub trait SemanticHooks {
886    /// Whether generated lexers should route lifecycle callbacks through this
887    /// hook object.
888    ///
889    /// User hook implementations opt in by default. [`NoSemanticHooks`]
890    /// overrides this to keep generated lexers on the direct no-extension
891    /// token path.
892    const ENABLES_LEXER_LIFECYCLE: bool = true;
893
894    /// Whether this hook object may observe parser predicate transitions.
895    ///
896    /// Custom hooks default to conservative predicate handling so the fast
897    /// recognizer does not bypass a `sempred` implementation.
898    fn observes_parser_predicates(&self) -> bool {
899        true
900    }
901
902    /// Whether this hook object may override interpreted parser decisions.
903    ///
904    /// This remains disabled by default so ordinary generated parsers retain
905    /// the fast recognizer path.
906    fn observes_parser_decisions(&self) -> bool {
907        false
908    }
909
910    /// Overrides one interpreted parser decision with a one-based alternative.
911    ///
912    /// Returning `None` leaves normal adaptive prediction in control. Hooks
913    /// that return an alternative own any one-shot or input-index filtering
914    /// they require.
915    fn parser_decision_override(
916        &mut self,
917        decision: usize,
918        input_index: usize,
919        alternative_count: usize,
920    ) -> Option<usize> {
921        let _ = (decision, input_index, alternative_count);
922        None
923    }
924
925    fn sempred<S>(
926        &mut self,
927        ctx: &mut ParserSemCtx<'_, S>,
928        rule_index: usize,
929        pred_index: usize,
930    ) -> Option<bool>
931    where
932        S: TokenSource,
933    {
934        let _ = (ctx, rule_index, pred_index);
935        None
936    }
937
938    fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
939    where
940        S: TokenSource,
941    {
942        let _ = (ctx, action);
943        false
944    }
945
946    fn lexer_sempred<I>(
947        &mut self,
948        ctx: &mut LexerSemCtx<'_, I>,
949        rule_index: usize,
950        pred_index: usize,
951    ) -> Option<bool>
952    where
953        I: CharStream,
954    {
955        let _ = (ctx, rule_index, pred_index);
956        None
957    }
958
959    /// Runs a lexer custom action on the committed lexing path. Returns whether
960    /// the hook handled the action.
961    ///
962    /// The action runs post-accept, so `ctx` carries a mutable lexer borrow: a
963    /// hook may change lexer state, including [`LexerSemCtx::set_type`],
964    /// [`LexerSemCtx::set_channel`], mode changes, input consumption, and
965    /// queued prefix tokens, just like the closure-based `custom_action` API.
966    /// (The speculative predicate context in [`Self::lexer_sempred`] is a shared
967    /// borrow, so those mutators are inert there.)
968    fn lexer_action<I>(&mut self, ctx: &mut LexerSemCtx<'_, I>, action: LexerCustomAction) -> bool
969    where
970        I: CharStream,
971    {
972        let _ = (ctx, action);
973        false
974    }
975
976    /// Runs after runtime-owned lexer state has been reset for reuse.
977    ///
978    /// Implementations should clear extension-owned transient state here.
979    fn lexer_reset<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
980    where
981        I: CharStream,
982    {
983        let _ = ctx;
984    }
985
986    /// Runs before the runtime returns a queued token or starts a new ATN
987    /// token match.
988    ///
989    /// The callback also runs between internal `skip`/`more` matches, so it
990    /// observes every point where another ATN match may start.
991    fn lexer_before_token<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
992    where
993        I: CharStream,
994    {
995        let _ = ctx;
996    }
997
998    /// Runs after the accepted path's portable and custom actions, but before
999    /// the token span is finalized and emitted.
1000    ///
1001    /// Accepted paths that selected `skip` or `more` are included, and the hook
1002    /// may observe or override that pending token type.
1003    ///
1004    /// This callback has no synthetic ATN coordinate. It therefore also runs
1005    /// for accepted rules that contain no action or predicate.
1006    fn lexer_after_accept<I>(&mut self, ctx: &mut LexerLifecycleCtx<'_, I>)
1007    where
1008        I: CharStream,
1009    {
1010        let _ = ctx;
1011    }
1012
1013    /// Observes a token after committed lexer actions and portable commands
1014    /// have run and the token has been emitted, immediately before it is
1015    /// returned to the token stream.
1016    ///
1017    /// Hidden and custom-channel tokens are included. `skip` and intermediate
1018    /// `more` matches do not produce callbacks.
1019    fn lexer_token_emitted(&mut self, token: TokenView<'_>) {
1020        let _ = token;
1021    }
1022}
1023
1024/// Default hook object used by parsers that do not need user-supplied
1025/// semantics.
1026#[derive(Clone, Copy, Debug, Default)]
1027pub struct NoSemanticHooks;
1028
1029impl SemanticHooks for NoSemanticHooks {
1030    const ENABLES_LEXER_LIFECYCLE: bool = false;
1031
1032    fn observes_parser_predicates(&self) -> bool {
1033        false
1034    }
1035}
1036
1037/// Parser semantic predicate rendered from a supported target template.
1038///
1039/// The metadata recognizer evaluates these at the token-stream index where the
1040/// predicate transition is reached. Unsupported or absent predicate templates
1041/// remain unconditional so existing generated parsers keep their previous
1042/// behavior unless the generator opts into this table.
1043#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1044pub enum ParserPredicate {
1045    True,
1046    False,
1047    /// Predicate that always fails and carries ANTLR's `<fail='...'>` message.
1048    FalseWithMessage {
1049        message: &'static str,
1050    },
1051    /// Target-template test helper that reports predicate evaluation before
1052    /// returning the wrapped boolean value.
1053    Invoke {
1054        value: bool,
1055    },
1056    LookaheadTextEquals {
1057        offset: isize,
1058        text: &'static str,
1059    },
1060    LookaheadNotEquals {
1061        offset: isize,
1062        token_type: i32,
1063    },
1064    /// Checks that the last two consumed visible tokens were adjacent in the
1065    /// token stream. Used by C# parser predicates for split operator tokens.
1066    TokenPairAdjacent,
1067    /// Checks a generated parser context child by rule index and text.
1068    ///
1069    /// If the child is absent the predicate succeeds, matching target helpers
1070    /// that treat incomplete or non-matching contexts as non-restrictive.
1071    ContextChildRuleTextNotEquals {
1072        rule_index: usize,
1073        text: &'static str,
1074    },
1075    /// Compares the current rule invocation's integer argument with a literal
1076    /// value from a supported `ValEquals("$i", "...")` target template.
1077    LocalIntEquals {
1078        value: i64,
1079    },
1080    /// Checks ANTLR-style raw predicates like `5 >= $_p` against the current
1081    /// rule invocation's integer argument.
1082    LocalIntLessOrEqual {
1083        value: i64,
1084    },
1085    /// Compares a generated parser integer member modulo a literal value.
1086    MemberModuloEquals {
1087        member: usize,
1088        modulus: i64,
1089        value: i64,
1090        equals: bool,
1091    },
1092    /// Compares a generated parser integer member with a literal value.
1093    MemberEquals {
1094        member: usize,
1095        value: i64,
1096        equals: bool,
1097    },
1098}
1099
1100impl ParserPredicate {
1101    /// Lowers the legacy predicate metadata variant into `SemIR`.
1102    ///
1103    /// This is the compatibility adapter for generated parsers produced while
1104    /// the runtime still emitted closed enum tables. Newer generated parsers
1105    /// emit `SemIR` directly.
1106    pub fn lower_into_semir(self, ir: &mut SemIr) -> ExprId {
1107        match self {
1108            Self::True => ir.expr(PExpr::Bool(true)),
1109            Self::False | Self::FalseWithMessage { .. } => ir.expr(PExpr::Bool(false)),
1110            Self::Invoke { value } => ir.expr(PExpr::EvalTrace(value)),
1111            Self::LookaheadTextEquals { offset, text } => {
1112                let token = ir.expr(PExpr::TokenText(offset));
1113                let text = ir.intern(text);
1114                let text = ir.expr(PExpr::Str(text));
1115                ir.expr(PExpr::Cmp(CmpOp::Eq, token, text))
1116            }
1117            Self::LookaheadNotEquals { offset, token_type } => {
1118                let actual = ir.expr(PExpr::La(offset));
1119                let expected = ir.expr(PExpr::Int(i64::from(token_type)));
1120                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
1121            }
1122            Self::TokenPairAdjacent => ir.expr(PExpr::TokenIndexAdjacent),
1123            Self::ContextChildRuleTextNotEquals { rule_index, text } => {
1124                let actual = ir.expr(PExpr::CtxRuleText(rule_index));
1125                let expected = ir.intern(text);
1126                let expected = ir.expr(PExpr::Str(expected));
1127                ir.expr(PExpr::Cmp(CmpOp::Ne, actual, expected))
1128            }
1129            Self::LocalIntEquals { value } => local_arg_comparison(ir, CmpOp::Eq, value),
1130            Self::LocalIntLessOrEqual { value } => local_arg_comparison(ir, CmpOp::Le, value),
1131            Self::MemberModuloEquals {
1132                member,
1133                modulus,
1134                value,
1135                equals,
1136            } => {
1137                if modulus == 0 {
1138                    return ir.expr(PExpr::Bool(false));
1139                }
1140                let member = ir.expr(PExpr::Member(member));
1141                let modulus = ir.expr(PExpr::Int(modulus));
1142                let actual = ir.expr(PExpr::Arith(ArithOp::Mod, member, modulus));
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            Self::MemberEquals {
1151                member,
1152                value,
1153                equals,
1154            } => {
1155                let actual = ir.expr(PExpr::Member(member));
1156                let expected = ir.expr(PExpr::Int(value));
1157                ir.expr(PExpr::Cmp(
1158                    if equals { CmpOp::Eq } else { CmpOp::Ne },
1159                    actual,
1160                    expected,
1161                ))
1162            }
1163        }
1164    }
1165
1166    #[must_use]
1167    pub const fn failure_message(self) -> Option<&'static str> {
1168        match self {
1169            Self::FalseWithMessage { message } => Some(message),
1170            Self::True
1171            | Self::False
1172            | Self::Invoke { .. }
1173            | Self::LookaheadTextEquals { .. }
1174            | Self::LookaheadNotEquals { .. }
1175            | Self::TokenPairAdjacent
1176            | Self::ContextChildRuleTextNotEquals { .. }
1177            | Self::LocalIntEquals { .. }
1178            | Self::LocalIntLessOrEqual { .. }
1179            | Self::MemberModuloEquals { .. }
1180            | Self::MemberEquals { .. } => None,
1181        }
1182    }
1183}
1184
1185fn local_arg_comparison(ir: &mut SemIr, op: CmpOp, value: i64) -> ExprId {
1186    let local = ir.expr(PExpr::LocalArg);
1187    let absent = ir.expr(PExpr::IsNull(local));
1188    let expected = ir.expr(PExpr::Int(value));
1189    let comparison = ir.expr(PExpr::Cmp(op, local, expected));
1190    ir.expr(PExpr::Or([absent, comparison].into()))
1191}
1192
1193/// Policy for semantic predicate coordinates that have no runtime
1194/// implementation.
1195///
1196/// ANTLR grammars may embed target-language predicates that the metadata
1197/// generator could not translate into a [`ParserPredicate`] table entry. When
1198/// recognition reaches such a coordinate the runtime cannot know the grammar
1199/// author's intent, so the caller chooses how to proceed.
1200///
1201/// The default is [`Self::AssumeTrue`], matching the historical behavior of
1202/// this runtime. That default is deprecated and will change to [`Self::Error`]
1203/// in a future minor release; grammars relying on unconditional predicates
1204/// should opt in explicitly.
1205#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1206pub enum UnknownSemanticPolicy {
1207    /// Treat the predicate as passing, as if it were absent from the grammar.
1208    #[default]
1209    AssumeTrue,
1210    /// Treat the predicate as failing, removing the guarded alternative.
1211    AssumeFalse,
1212    /// Fail the parse with [`AntlrError::Unsupported`] naming every unknown
1213    /// coordinate that recognition evaluated.
1214    Error,
1215}
1216
1217/// Resolves a predicate coordinate that neither a translated table entry nor a
1218/// user hook could answer, applying the active [`UnknownSemanticPolicy`].
1219///
1220/// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded in `hits`
1221/// so the parse entry can surface every unresolved coordinate afterwards. Both
1222/// the legacy [`ParserPredicate`] path and the [`semir::PExpr::Hook`] path
1223/// funnel through here so a missing implementation is never silently coerced
1224/// to a boolean (design goal G1: never silently mis-parse).
1225fn apply_unknown_predicate_policy(
1226    policy: UnknownSemanticPolicy,
1227    rule_index: usize,
1228    pred_index: usize,
1229    hits: &mut Vec<(usize, usize)>,
1230) -> bool {
1231    match policy {
1232        UnknownSemanticPolicy::AssumeTrue => true,
1233        UnknownSemanticPolicy::AssumeFalse => false,
1234        UnknownSemanticPolicy::Error => {
1235            let coordinate = (rule_index, pred_index);
1236            if !hits.contains(&coordinate) {
1237                hits.push(coordinate);
1238            }
1239            false
1240        }
1241    }
1242}
1243
1244/// Interval-set of expected token types, displayable through a vocabulary —
1245/// the shape ANTLR's `getExpectedTokens().toString(vocabulary)` exposes to
1246/// generated test actions.
1247#[derive(Clone, Debug, Eq, PartialEq)]
1248pub struct ExpectedTokenSet {
1249    symbols: BTreeSet<i32>,
1250}
1251
1252impl ExpectedTokenSet {
1253    /// Formats the set using ANTLR token display names, e.g. `{'a', 'b'}`.
1254    #[must_use]
1255    pub fn to_token_string(&self, vocabulary: &Vocabulary) -> String {
1256        expected_symbols_display(&self.symbols, vocabulary)
1257    }
1258}
1259
1260/// Marker error strategy matching ANTLR's `BailErrorStrategy`.
1261///
1262/// The first syntax error aborts the parse instead of recovering. Generated
1263/// recognizers accept it through `set_error_handler(BailErrorStrategy::new())`.
1264#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1265pub struct BailErrorStrategy;
1266
1267impl BailErrorStrategy {
1268    #[must_use]
1269    pub const fn new() -> Self {
1270        Self
1271    }
1272}
1273
1274/// Prediction strategy requested by generated parser harnesses.
1275#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1276pub enum PredictionMode {
1277    /// Prefer the clean full-context outcome when alternatives reach the same
1278    /// input position.
1279    Ll,
1280    /// Preserve SLL's first-viable alternative bias at a decision, even when a
1281    /// later full-context alternative could avoid recovery.
1282    Sll,
1283    /// Full LL prediction with exact ambiguity detection for diagnostic runs.
1284    LlExactAmbigDetection,
1285}
1286
1287/// Integer argument metadata for a generated parser rule invocation.
1288///
1289/// ANTLR's serialized ATN does not retain Rust-target rule argument values, so
1290/// the generator records the rule-transition source state and the value that
1291/// should be visible to semantic predicates inside the callee.
1292#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1293pub struct ParserRuleArg {
1294    /// ATN state containing the rule transition that receives this argument.
1295    pub source_state: usize,
1296    /// Callee rule index for the transition.
1297    pub rule_index: usize,
1298    /// Literal fallback value to expose in the callee.
1299    pub value: i64,
1300    /// Whether the callee should inherit the caller's current integer argument.
1301    pub inherit_local: bool,
1302}
1303
1304/// Integer member mutation attached to an ATN action transition.
1305#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1306pub struct ParserMemberAction {
1307    /// ATN state containing the action transition.
1308    pub source_state: usize,
1309    /// Generator-assigned integer member id.
1310    pub member: usize,
1311    /// Delta applied when the action is reached on one speculative path.
1312    pub delta: i64,
1313}
1314
1315/// Integer return-value assignment attached to an ATN action transition.
1316///
1317/// Generated parsers use this metadata when target actions assign a simple
1318/// return field such as `$y=1000;`. The interpreter applies it while selecting
1319/// the recognized path so the finished parse tree can answer later
1320/// `$label.y` action templates.
1321#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1322pub struct ParserReturnAction {
1323    /// ATN state containing the action transition.
1324    pub source_state: usize,
1325    /// Rule index recorded by the serialized action transition.
1326    pub rule_index: usize,
1327    /// Return-field name as it appears in the grammar.
1328    pub name: &'static str,
1329    /// Literal integer value assigned by the action.
1330    pub value: i64,
1331}
1332
1333impl ParserMemberAction {
1334    /// Lowers this speculative member mutation into a `SemIR` action.
1335    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1336        let delta = ir.expr(PExpr::Int(self.delta));
1337        ParserSemanticAction {
1338            source_state: self.source_state,
1339            rule_index: usize::MAX,
1340            stmt: ir.stmt(AStmt::AddMember(self.member, delta)),
1341            speculative: true,
1342        }
1343    }
1344}
1345
1346impl ParserReturnAction {
1347    /// Lowers this committed return-value assignment into a `SemIR` action.
1348    pub fn lower_into_semir(self, ir: &mut SemIr) -> ParserSemanticAction {
1349        let name = ir.intern(self.name);
1350        let value = ir.expr(PExpr::Int(self.value));
1351        ParserSemanticAction {
1352            source_state: self.source_state,
1353            rule_index: self.rule_index,
1354            stmt: ir.stmt(AStmt::SetReturn(name, value)),
1355            speculative: false,
1356        }
1357    }
1358}
1359
1360/// Parser predicate coordinate lowered into [`SemIr`].
1361#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1362pub struct ParserSemanticPredicate {
1363    /// Serialized rule index that owns this predicate.
1364    pub rule_index: usize,
1365    /// Predicate index inside the owning rule.
1366    pub pred_index: usize,
1367    /// Root expression in the associated [`ParserSemantics::ir`] arena.
1368    pub expr: ExprId,
1369    /// ANTLR `<fail='...'>` message for predicates that intentionally fail.
1370    pub failure_message: Option<&'static str>,
1371}
1372
1373/// Parser action coordinate lowered into [`SemIr`].
1374#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1375pub struct ParserSemanticAction {
1376    /// ATN state containing the action transition.
1377    pub source_state: usize,
1378    /// Serialized rule index recorded by the action transition.
1379    pub rule_index: usize,
1380    /// Root statement in the associated [`ParserSemantics::ir`] arena.
1381    pub stmt: StmtId,
1382    /// Whether this action may run on speculative recognition paths.
1383    pub speculative: bool,
1384}
1385
1386/// Data-driven semantic tables emitted by generated parsers.
1387///
1388/// This is the runtime representation for issue #9's `SemIR` path. Existing
1389/// `ParserPredicate`, `ParserMemberAction`, and `ParserReturnAction` tables
1390/// remain accepted as deprecated adapters for generated code produced before
1391/// this table existed.
1392#[derive(Clone, Debug, Default, Eq, PartialEq)]
1393pub struct ParserSemantics {
1394    pub ir: SemIr,
1395    pub predicates: Vec<ParserSemanticPredicate>,
1396    pub actions: Vec<ParserSemanticAction>,
1397}
1398
1399/// Optional generated-runtime metadata for metadata-driven parser execution.
1400#[derive(Clone, Copy, Debug, Default)]
1401pub struct ParserRuntimeOptions<'a> {
1402    /// Rule indexes whose `@init` actions should run at rule entry or be
1403    /// returned for legacy replay when no semantic hook handles them.
1404    pub init_action_rules: &'a [usize],
1405    /// Stable parser-action indexes keyed by authored ATN source state.
1406    ///
1407    /// A non-empty table selects committed interpreted execution: mapped
1408    /// actions run at their grammar position instead of being replayed after
1409    /// the complete rule has been recognized.
1410    pub action_indices: &'a [(usize, usize)],
1411    /// Whether generated parse-tree contexts should retain alternative numbers.
1412    pub track_alt_numbers: bool,
1413    /// Whether generated typed contexts should retain private dispatch alternatives.
1414    ///
1415    /// Unlike `track_alt_numbers`, this metadata does not affect the public
1416    /// alternative number or parse-tree rendering.
1417    #[doc(hidden)]
1418    pub track_context_alt_numbers: bool,
1419    /// Semantic predicate table keyed by serialized `(rule_index, pred_index)`.
1420    pub predicates: &'a [(usize, usize, ParserPredicate)],
1421    /// `SemIR` predicate/action table emitted by newer generated parsers.
1422    pub semantics: Option<&'a ParserSemantics>,
1423    /// Rule-call integer argument table keyed by ATN source state.
1424    pub rule_args: &'a [ParserRuleArg],
1425    /// Integer member mutations keyed by ATN action source state.
1426    pub member_actions: &'a [ParserMemberAction],
1427    /// Integer return assignments keyed by ATN action source state.
1428    pub return_actions: &'a [ParserReturnAction],
1429    /// How to evaluate semantic predicate coordinates absent from
1430    /// `predicates`.
1431    pub unknown_predicate_policy: UnknownSemanticPolicy,
1432}
1433
1434pub trait Parser: Recognizer {
1435    /// Reports whether generated parser rules should build parse-tree nodes
1436    /// while recognizing input.
1437    fn build_parse_trees(&self) -> bool;
1438
1439    /// Enables or disables parse-tree construction for subsequent rule calls.
1440    fn set_build_parse_trees(&mut self, build: bool);
1441
1442    /// Returns the number of parser syntax errors recorded by committed parse
1443    /// paths so far.
1444    fn number_of_syntax_errors(&self) -> usize {
1445        0
1446    }
1447
1448    /// Reports whether prediction diagnostic-listener messages are emitted
1449    /// during parser ATN recognition.
1450    fn report_diagnostic_errors(&self) -> bool {
1451        false
1452    }
1453
1454    /// Enables or disables ANTLR-style prediction diagnostics for subsequent
1455    /// rule calls.
1456    fn set_report_diagnostic_errors(&mut self, _report: bool) {}
1457
1458    /// Reports the prediction strategy used when selecting among alternatives.
1459    fn prediction_mode(&self) -> PredictionMode {
1460        PredictionMode::Ll
1461    }
1462
1463    /// Sets the prediction strategy for subsequent rule calls.
1464    fn set_prediction_mode(&mut self, _mode: PredictionMode) {}
1465
1466    /// Maximum rule-nesting depth accepted before the parse aborts, or `None`
1467    /// for unlimited (the default).
1468    fn max_rule_depth(&self) -> Option<usize> {
1469        None
1470    }
1471
1472    /// Bounds the rule-nesting depth for subsequent rule calls.
1473    ///
1474    /// Deeply nested input is parsed safely regardless (rule recursion grows
1475    /// onto a segmented stack), but each nesting level still costs CPU and
1476    /// tree memory. Callers parsing untrusted input can cap that work: when
1477    /// the limit is exceeded the parse stops with a positioned syntax error
1478    /// instead of consuming unbounded resources. The measure counts rule
1479    /// frames plus left-recursive operator expansions, matching what an
1480    /// upstream-ANTLR rule-entry listener observes.
1481    ///
1482    /// The cap is enforced by generated recursive-descent rule bodies. When
1483    /// one is set, generated dispatch routes ATN-preferred rules through
1484    /// their generated bodies too, trading that fast path for enforcement.
1485    /// Rules the generator emitted no body for (interpreter-only fallback)
1486    /// do not check the cap.
1487    fn set_max_rule_depth(&mut self, _depth: Option<usize>) {}
1488
1489    /// Registers a listener for committed rule enter/exit events during
1490    /// recognition (ANTLR's `addParseListener`). See [`ParseListener`] for
1491    /// the delivery contract. The default implementation drops the listener;
1492    /// [`BaseParser`] and generated parsers deliver events.
1493    fn add_parse_listener(&mut self, _listener: Box<dyn ParseListener>) {}
1494
1495    /// Removes every registered parse listener and returns them, dropping
1496    /// any sticky abort a removed listener had requested.
1497    fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
1498        Vec::new()
1499    }
1500}
1501
1502#[derive(Debug)]
1503struct LeftRecursiveCallerOverlap {
1504    atn_key: SharedAtnCacheKey,
1505    state_number: usize,
1506    symbol: i32,
1507    context_version: usize,
1508    overlaps: bool,
1509}
1510
1511const LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE: usize = 16;
1512
1513#[derive(Debug)]
1514pub struct BaseParser<S, H = NoSemanticHooks> {
1515    input: CommonTokenStream<S>,
1516    tree: ParseTreeStorage,
1517    data: RecognizerData,
1518    semantic_hooks: H,
1519    decision_override_generation: usize,
1520    build_parse_trees: bool,
1521    syntax_errors: usize,
1522    report_diagnostic_errors: bool,
1523    prediction_mode: PredictionMode,
1524    prediction_diagnostics: Vec<ParserDiagnostic>,
1525    reported_prediction_diagnostics: BTreeSet<(usize, usize, String)>,
1526    generated_parser_diagnostics: Vec<ParserDiagnostic>,
1527    generated_sync_expected: Option<TokenBitSet>,
1528    generated_recovery_error_index: Option<usize>,
1529    generated_recovery_error_states: BTreeSet<isize>,
1530    int_members: MemberEnv,
1531    rule_context_stack: Vec<RuleContextFrame>,
1532    rule_context_version: usize,
1533    left_recursive_caller_overlap_cache:
1534        [Option<LeftRecursiveCallerOverlap>; LEFT_RECURSIVE_CALLER_OVERLAP_CACHE_SIZE],
1535    pending_invoking_states: Vec<isize>,
1536    precedence_stack: Vec<i32>,
1537    /// Predicate side effects are observable in a few target-template tests;
1538    /// speculative recognition may revisit the same coordinate, so replay it
1539    /// once per parser instance.
1540    invoked_predicates: Vec<(usize, usize)>,
1541    /// Bail error strategy: the first syntax error aborts the parse instead of
1542    /// recovering (ANTLR's `BailErrorStrategy`). Generated recognizers set it
1543    /// through `set_error_handler(BailErrorStrategy::new())`.
1544    bail_on_error: bool,
1545    /// Parse listeners receiving committed rule enter/exit events during
1546    /// recognition (ANTLR's `addParseListener`). Empty in the default
1547    /// configuration, and every dispatch site is gated on emptiness so the
1548    /// unused feature costs one predictable branch per rule boundary.
1549    parse_listeners: Vec<ParseListenerSlot>,
1550    /// Sticky abort requested by a parse listener's `enter_every_rule`.
1551    /// Mirrors `rule_depth_error`: rule-level recovery absorbs the error like
1552    /// any rule failure, so the flag stays set until the top-level entry
1553    /// drains it and fails the parse.
1554    parse_listener_abort: Option<AntlrError>,
1555    /// Optional cap on rule-nesting depth for adversarial-input hardening.
1556    /// `None` (default) parses unbounded nesting; `Some(n)` aborts the parse
1557    /// with a positioned syntax error once `n` rule frames are exceeded.
1558    max_rule_depth: Option<usize>,
1559    /// Sticky depth-cap violation. Rule-level recovery would otherwise absorb
1560    /// the error and keep parsing; once set, every subsequent rule entry fails
1561    /// immediately and the top-level entry returns this error even when
1562    /// recovery produced a tree.
1563    rule_depth_error: Option<AntlrError>,
1564    /// Left-recursive expansions currently deepening the parse tree. Each
1565    /// operator iteration wraps the previous context one level deeper without
1566    /// pushing a rule frame, so the depth cap must count these separately —
1567    /// upstream ANTLR fires a rule-entry listener event for exactly this case
1568    /// (`Parser.pushNewRecursionContext` → `triggerEnterRuleEvent`).
1569    recursion_expansions: usize,
1570    /// Per-invocation snapshots of [`Self::recursion_expansions`], pushed by
1571    /// `enter_recursion_rule` and restored by `unroll_recursion_context`, so a
1572    /// finished left-recursive rule releases the depth its expansions added.
1573    recursion_expansion_marks: Vec<usize>,
1574    /// How to evaluate predicate coordinates missing from the active
1575    /// predicate table. Set from [`ParserRuntimeOptions`] at each parse entry.
1576    unknown_predicate_policy: UnknownSemanticPolicy,
1577    /// Unknown predicate coordinates evaluated by the current parse, recorded
1578    /// so [`UnknownSemanticPolicy::Error`] can report them after recognition.
1579    unknown_predicate_hits: Vec<(usize, usize)>,
1580    /// Committed parser action coordinates offered to [`SemanticHooks::action`]
1581    /// that no hook handled, recorded so a generated `hook`/error-disposed
1582    /// action fails loud instead of being silently dropped. Keyed by
1583    /// `(rule_index, source_state)`.
1584    unhandled_action_hits: Vec<(usize, usize)>,
1585    /// Per-parse rule FIRST-set cache keyed by rule start state. This keeps
1586    /// hot rule-transition checks to a vector lookup after the first visit
1587    /// while the thread-local shared ATN cache still owns the cross-parse
1588    /// computed value.
1589    rule_first_set_cache: Vec<Option<Rc<FirstSet>>>,
1590    /// Per-state expected-symbol cache. `state_expected_symbols` walks every
1591    /// epsilon-reachable consuming transition and shows up as a hot loop in
1592    /// `next_recovery_context` and recovery diagnostics on long inputs.
1593    /// Keying on `state_number` and sharing the result through `Rc` removes
1594    /// repeated DFS plus per-call `BTreeSet` allocations.
1595    state_expected_cache: FxHashMap<usize, Rc<BTreeSet<i32>>>,
1596    /// Same expected-symbol cache as a bitset for generated parser sync.
1597    /// Successful parses only need `contains` and union; keeping that path out
1598    /// of `BTreeSet` avoids tree allocation for every nullable loop/optional
1599    /// check and defers deterministic formatting to diagnostics.
1600    state_expected_token_cache: FxHashMap<usize, Rc<TokenBitSet>>,
1601    /// Per-state cache for whether a return state can finish its owning rule
1602    /// without consuming more input. Generated-parser sync uses this to walk
1603    /// parent prediction contexts for nullable exits without paying repeated
1604    /// epsilon-closure searches on every loop or optional decision.
1605    rule_stop_reach_cache: Vec<Option<bool>>,
1606    /// Per-parser interner for `recovery_symbols` sets. Speculative recursion
1607    /// threads the same epsilon-recovery context through hundreds of follow
1608    /// states; sharing `Rc<BTreeSet<i32>>` instances lets clones reduce to a
1609    /// reference bump and lets the memo key hash by pointer.
1610    recovery_symbols_intern: FxHashMap<Rc<BTreeSet<i32>>, Rc<BTreeSet<i32>>>,
1611    /// Per-decision-state look-1 cache. Built lazily so grammars that rarely
1612    /// touch a given decision state still pay no upfront cost; once cached,
1613    /// the recognizer prunes alternatives whose look-1 cannot accept the
1614    /// current lookahead, letting common SLL decisions reduce to a single
1615    /// transition walk instead of a full speculative fan-out.
1616    decision_lookahead_cache: FxHashMap<usize, Rc<DecisionLookahead>>,
1617    /// Caches the LL(1) alt selection per `(state, lookahead_token)`.
1618    /// Each multi-trans visit asks "given this decision state and this
1619    /// lookahead token, which alt do I commit to?" Hitting this cache
1620    /// turns the question into a hashmap probe instead of re-scanning
1621    /// the decision's per-transition FIRST sets every visit.
1622    ll1_decision_cache: FxHashMap<(usize, i32), Option<usize>>,
1623    /// Predicate results shared by the fast recognizer's clean and recovery
1624    /// attempts. The eligible fast path keeps every runtime-provided input
1625    /// fixed, and custom predicate hooks are required to be replay-safe.
1626    fast_predicate_cache: FxHashMap<(usize, usize, usize), bool>,
1627    /// Cache for whether an ATN state can reach itself without consuming
1628    /// input. Only those states need the recursive recognizer's
1629    /// `(state, token-index)` cycle guard. The companion ATN key lets this
1630    /// grammar-static cache survive parser resets without reusing state
1631    /// coordinates after the parser is driven against a different ATN.
1632    empty_cycle_cache: Vec<Option<bool>>,
1633    empty_cycle_cache_atn: Option<SharedAtnCacheKey>,
1634    /// Probe state for deciding whether clean-pass memo entries are worth
1635    /// storing for the current parse.
1636    clean_memo_mode: CleanMemoMode,
1637    clean_memo_probe_seen: FxHashSet<FastRecognizeKey>,
1638    clean_memo_probe_samples: usize,
1639    clean_memo_probe_repeats: usize,
1640    clean_memo_sparse_samples: usize,
1641    /// Reusable cycle and memo storage for one top-level fast recognition.
1642    fast_recognize_scratch: FastRecognizeTopScratch,
1643    /// Reusable direct-index/hash storage for clean speculative endpoints.
1644    fast_outcome_dedup: FastOutcomeDedupScratch,
1645    /// Empty recovery-symbols singleton used as the default at rule entry and
1646    /// after token consumption.
1647    empty_recovery_symbols: Rc<BTreeSet<i32>>,
1648    /// Whether the fast recognizer's FIRST-set prefilter is enabled. The
1649    /// prefilter trims speculative rule calls whose called rule cannot
1650    /// match the current lookahead, but it also bypasses single-token
1651    /// insertion / deletion recovery that ANTLR runs at the rule's first
1652    /// consuming transition. `parse_atn_rule` flips this off and retries
1653    /// when the first pass produces no clean outcome so the runtime can
1654    /// repair inputs the reference parser would have repaired.
1655    fast_first_set_prefilter: bool,
1656    /// Whether the fast recognizer should explore parser error-recovery paths.
1657    /// Public rule parsing starts with this disabled for the common valid-input
1658    /// path and enables it only for the retry that needs ANTLR-style repairs.
1659    fast_recovery_enabled: bool,
1660    /// Whether the fast recognizer should record terminal-token nodes while
1661    /// speculating. Clean valid-input parsing can reconstruct terminals from
1662    /// selected rule spans after recognition, avoiding many speculative
1663    /// nodes that are thrown away with losing paths.
1664    fast_token_nodes_enabled: bool,
1665    /// Whether fast recognition should retain private/public rule alternatives
1666    /// in deferred tree metadata.
1667    fast_track_alt_numbers: bool,
1668    /// Parser-owned append-only storage for speculative recognition output.
1669    /// Each public interpreted-rule entry clears lengths while retaining
1670    /// bounded backing capacities for parser reuse.
1671    recognition_arena: RecognitionArena,
1672    last_recognition_arena_root: NodeSeqId,
1673    last_recognition_arena_diagnostics: DiagnosticSeqId,
1674}
1675
1676/// Rollback marker for speculative generated parser paths.
1677#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1678pub struct GeneratedDiagnosticsCheckpoint {
1679    diagnostics_len: usize,
1680    syntax_errors: usize,
1681    tree: ParseTreeCheckpoint,
1682}
1683
1684/// Storage and reachability counters for the most recent interpreted-rule
1685/// recognition arena.
1686#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1687pub struct RecognitionArenaStats {
1688    pub total_nodes: usize,
1689    pub live_nodes: usize,
1690    pub dead_nodes: usize,
1691    pub node_capacity: usize,
1692    pub total_links: usize,
1693    pub live_links: usize,
1694    pub dead_links: usize,
1695    pub link_capacity: usize,
1696    pub total_extras: usize,
1697    pub live_extras: usize,
1698    pub dead_extras: usize,
1699    pub extra_capacity: usize,
1700}
1701
1702#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1703struct RuleContextFrame {
1704    rule_index: usize,
1705    invoking_state: isize,
1706}
1707
1708#[derive(Clone, Debug, Eq, PartialEq)]
1709struct RecognizeOutcome {
1710    index: usize,
1711    consumed_eof: bool,
1712    alt_number: usize,
1713    member_values: MemberEnv,
1714    return_values: BTreeMap<String, i64>,
1715    diagnostics: DiagnosticSeqId,
1716    decisions: Vec<usize>,
1717    actions: Vec<ParserAction>,
1718    nodes: NodeSeqId,
1719}
1720
1721#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1722struct FastRecognizeOutcome {
1723    index: usize,
1724    consumed_eof: bool,
1725    diagnostics: DiagnosticSeqId,
1726    deferred_nodes: FastDeferredNodeId,
1727    /// Head of the speculative parse-tree fragment in the parser-owned arena.
1728    /// Copying an outcome copies this compact ID; prepending appends one
1729    /// `SeqLink` without allocating an individual node or list tail.
1730    nodes: NodeSeqId,
1731}
1732
1733#[derive(Debug, Default)]
1734struct FastRecognizeTopScratch {
1735    visiting: FxHashSet<FastRecognizeKey>,
1736    memo: FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
1737}
1738
1739impl FastRecognizeTopScratch {
1740    fn prepare(&mut self, memo_capacity: usize) {
1741        self.visiting.clear();
1742        self.visiting.reserve(FAST_RECOGNIZE_VISITING_CAPACITY);
1743        self.memo.clear();
1744        self.memo.reserve(memo_capacity);
1745    }
1746
1747    fn release_oversized_memo(&mut self) {
1748        self.memo.clear();
1749        if self.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY {
1750            self.memo = FxHashMap::default();
1751        }
1752    }
1753}
1754
1755fn fast_recognize_memo_capacity(buffered_tokens: usize) -> usize {
1756    buffered_tokens.saturating_mul(8).clamp(
1757        FAST_RECOGNIZE_MIN_MEMO_CAPACITY,
1758        FAST_RECOGNIZE_MAX_MEMO_CAPACITY,
1759    )
1760}
1761
1762#[derive(Debug, Default)]
1763struct FastOutcomeDedupScratch {
1764    dense_words: Vec<u64>,
1765    touched_dense_words: Vec<u32>,
1766    sparse_keys: FxHashSet<(usize, bool)>,
1767}
1768
1769/// Handle into the parser-owned deferred tree rope.
1770///
1771/// The sentinel keeps outcomes and repetition paths compact without an
1772/// `Option` discriminant or per-node reference counting.
1773#[repr(transparent)]
1774#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1775struct FastDeferredNodeId(u32);
1776
1777impl FastDeferredNodeId {
1778    const EMPTY: Self = Self(u32::MAX);
1779
1780    const fn is_empty(self) -> bool {
1781        self.0 == Self::EMPTY.0
1782    }
1783}
1784
1785impl Default for FastDeferredNodeId {
1786    fn default() -> Self {
1787        Self::EMPTY
1788    }
1789}
1790
1791#[repr(transparent)]
1792#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1793struct FastDeferredRuleId(u32);
1794
1795/// One immutable deferred-tree rope record in `RecognitionArena`.
1796#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1797enum FastDeferredNode {
1798    Fragment(NodeSeqId),
1799    Rule(FastDeferredRuleId),
1800    Alternative(u32),
1801    LeftRecursiveBoundary {
1802        rule_index: u32,
1803    },
1804    Concat {
1805        prefix: FastDeferredNodeId,
1806        suffix: FastDeferredNodeId,
1807    },
1808}
1809
1810#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1811struct FastDeferredRule {
1812    rule_index: u32,
1813    invoking_state: i32,
1814    start_index: u32,
1815    stop_index: Option<u32>,
1816    deferred_children: FastDeferredNodeId,
1817    children: NodeSeqId,
1818}
1819
1820#[repr(transparent)]
1821#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1822struct RecognizedNodeId(u32);
1823
1824#[repr(transparent)]
1825#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1826struct NodeSeqId(u32);
1827
1828impl NodeSeqId {
1829    const EMPTY: Self = Self(u32::MAX);
1830
1831    const fn is_empty(self) -> bool {
1832        self.0 == Self::EMPTY.0
1833    }
1834}
1835
1836impl Default for NodeSeqId {
1837    fn default() -> Self {
1838        Self::EMPTY
1839    }
1840}
1841
1842#[repr(transparent)]
1843#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1844struct DiagnosticSeqId(u32);
1845
1846impl DiagnosticSeqId {
1847    const EMPTY: Self = Self(u32::MAX);
1848
1849    const fn is_empty(self) -> bool {
1850        self.0 == Self::EMPTY.0
1851    }
1852}
1853
1854impl Default for DiagnosticSeqId {
1855    fn default() -> Self {
1856        Self::EMPTY
1857    }
1858}
1859
1860#[repr(transparent)]
1861#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1862struct RecognitionExtraId(u32);
1863
1864#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1865struct SeqLink {
1866    head: RecognizedNodeId,
1867    tail: NodeSeqId,
1868}
1869
1870#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1871struct DiagnosticLink {
1872    head: RecognitionExtraId,
1873    tail: DiagnosticSeqId,
1874}
1875
1876struct ArenaRuleSpec {
1877    rule_index: usize,
1878    invoking_state: isize,
1879    alt_number: usize,
1880    start_index: usize,
1881    stop_index: Option<usize>,
1882    return_values: BTreeMap<String, i64>,
1883    children: NodeSeqId,
1884}
1885
1886/// Compact speculative node record. Common records contain only IDs and
1887/// scalars; missing-token text and generated return values live in `extras`.
1888#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1889enum ArenaRecognizedNode {
1890    Token {
1891        token: TokenId,
1892    },
1893    ErrorToken {
1894        token: TokenId,
1895    },
1896    MissingToken {
1897        extra: RecognitionExtraId,
1898    },
1899    Rule {
1900        rule_index: u32,
1901        invoking_state: i32,
1902        alt_number: u32,
1903        start_index: u32,
1904        stop_index: Option<u32>,
1905        return_values: Option<RecognitionExtraId>,
1906        children: NodeSeqId,
1907    },
1908    /// Marker emitted at a precedence-rule loop entry where ANTLR would call
1909    /// `pushNewRecursionContext`. Folded into a wrapper rule node before the
1910    /// public rule entry hands the tree to the caller.
1911    LeftRecursiveBoundary {
1912        rule_index: u32,
1913        alt_number: u32,
1914    },
1915}
1916
1917#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1918enum RecognitionExtra {
1919    MissingToken {
1920        token_type: i32,
1921        at_index: u32,
1922        text: String,
1923    },
1924    ReturnValues(BTreeMap<String, i64>),
1925    Diagnostic(ParserDiagnostic),
1926}
1927
1928#[derive(Debug, Default)]
1929struct RecognitionArena {
1930    nodes: Vec<ArenaRecognizedNode>,
1931    seq_links: Vec<SeqLink>,
1932    diagnostic_links: Vec<DiagnosticLink>,
1933    extras: Vec<RecognitionExtra>,
1934    deferred_nodes: Vec<FastDeferredNode>,
1935    deferred_rules: Vec<FastDeferredRule>,
1936}
1937
1938// Preserve normal parser reuse while preventing one pathological parse from
1939// pinning an arbitrarily large arena for the parser's remaining lifetime.
1940const MAX_RETAINED_RECOGNITION_NODES: usize = 131_072;
1941const MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS: usize = 262_144;
1942const MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS: usize = 65_536;
1943const MAX_RETAINED_RECOGNITION_EXTRAS: usize = 32_768;
1944const MAX_RETAINED_FAST_DEFERRED_NODES: usize = 262_144;
1945const MAX_RETAINED_FAST_DEFERRED_RULES: usize = 131_072;
1946
1947impl RecognitionArena {
1948    fn reset(&mut self) {
1949        reset_arena_vec(&mut self.nodes, MAX_RETAINED_RECOGNITION_NODES);
1950        reset_arena_vec(&mut self.seq_links, MAX_RETAINED_RECOGNITION_SEQUENCE_LINKS);
1951        reset_arena_vec(
1952            &mut self.diagnostic_links,
1953            MAX_RETAINED_RECOGNITION_DIAGNOSTIC_LINKS,
1954        );
1955        reset_arena_vec(&mut self.extras, MAX_RETAINED_RECOGNITION_EXTRAS);
1956        reset_arena_vec(&mut self.deferred_nodes, MAX_RETAINED_FAST_DEFERRED_NODES);
1957        reset_arena_vec(&mut self.deferred_rules, MAX_RETAINED_FAST_DEFERRED_RULES);
1958    }
1959
1960    fn push_node(&mut self, node: ArenaRecognizedNode) -> RecognizedNodeId {
1961        let id = RecognizedNodeId(
1962            u32::try_from(self.nodes.len()).expect("recognition node arena fits in u32"),
1963        );
1964        self.nodes.push(node);
1965        id
1966    }
1967
1968    fn push_extra(&mut self, extra: RecognitionExtra) -> RecognitionExtraId {
1969        let id = RecognitionExtraId(
1970            u32::try_from(self.extras.len()).expect("recognition extra arena fits in u32"),
1971        );
1972        self.extras.push(extra);
1973        id
1974    }
1975
1976    fn prepend(&mut self, tail: NodeSeqId, head: RecognizedNodeId) -> NodeSeqId {
1977        let id = NodeSeqId(
1978            u32::try_from(self.seq_links.len()).expect("node sequence arena fits in u32"),
1979        );
1980        self.seq_links.push(SeqLink { head, tail });
1981        id
1982    }
1983
1984    fn push_deferred_node(&mut self, node: FastDeferredNode) -> FastDeferredNodeId {
1985        let id = FastDeferredNodeId(
1986            u32::try_from(self.deferred_nodes.len()).expect("deferred node arena fits in u32"),
1987        );
1988        self.deferred_nodes.push(node);
1989        id
1990    }
1991
1992    fn push_deferred_rule(&mut self, rule: FastDeferredRule) -> FastDeferredRuleId {
1993        let id = FastDeferredRuleId(
1994            u32::try_from(self.deferred_rules.len()).expect("deferred rule arena fits in u32"),
1995        );
1996        self.deferred_rules.push(rule);
1997        id
1998    }
1999
2000    fn deferred_fragment(&mut self, nodes: NodeSeqId) -> FastDeferredNodeId {
2001        if nodes.is_empty() {
2002            FastDeferredNodeId::EMPTY
2003        } else {
2004            self.push_deferred_node(FastDeferredNode::Fragment(nodes))
2005        }
2006    }
2007
2008    fn deferred_rule_node(&mut self, rule: FastDeferredRule) -> FastDeferredNodeId {
2009        let rule = self.push_deferred_rule(rule);
2010        self.push_deferred_node(FastDeferredNode::Rule(rule))
2011    }
2012
2013    fn deferred_alternative(&mut self, alt_number: usize) -> FastDeferredNodeId {
2014        self.push_deferred_node(FastDeferredNode::Alternative(
2015            u32::try_from(alt_number).expect("alternative number fits in u32"),
2016        ))
2017    }
2018
2019    fn deferred_left_recursive_boundary(&mut self, rule_index: usize) -> FastDeferredNodeId {
2020        self.push_deferred_node(FastDeferredNode::LeftRecursiveBoundary {
2021            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
2022        })
2023    }
2024
2025    fn concat_deferred_nodes(
2026        &mut self,
2027        prefix: FastDeferredNodeId,
2028        suffix: FastDeferredNodeId,
2029    ) -> FastDeferredNodeId {
2030        if prefix.is_empty() {
2031            return suffix;
2032        }
2033        if suffix.is_empty() {
2034            return prefix;
2035        }
2036        self.push_deferred_node(FastDeferredNode::Concat { prefix, suffix })
2037    }
2038
2039    fn deferred_node(&self, id: FastDeferredNodeId) -> FastDeferredNode {
2040        self.deferred_nodes[id.0 as usize]
2041    }
2042
2043    fn deferred_rule(&self, id: FastDeferredRuleId) -> FastDeferredRule {
2044        self.deferred_rules[id.0 as usize]
2045    }
2046
2047    fn prepend_diagnostic(
2048        &mut self,
2049        tail: DiagnosticSeqId,
2050        diagnostic: ParserDiagnostic,
2051    ) -> DiagnosticSeqId {
2052        let head = self.push_extra(RecognitionExtra::Diagnostic(diagnostic));
2053        self.prepend_diagnostic_id(tail, head)
2054    }
2055
2056    fn prepend_diagnostic_id(
2057        &mut self,
2058        tail: DiagnosticSeqId,
2059        head: RecognitionExtraId,
2060    ) -> DiagnosticSeqId {
2061        let id = DiagnosticSeqId(
2062            u32::try_from(self.diagnostic_links.len())
2063                .expect("diagnostic sequence arena fits in u32"),
2064        );
2065        self.diagnostic_links.push(DiagnosticLink { head, tail });
2066        id
2067    }
2068
2069    fn concat_diagnostics(
2070        &mut self,
2071        prefix: DiagnosticSeqId,
2072        mut suffix: DiagnosticSeqId,
2073    ) -> DiagnosticSeqId {
2074        if prefix.is_empty() {
2075            return suffix;
2076        }
2077        if suffix.is_empty() {
2078            return prefix;
2079        }
2080        let mut reversed = DiagnosticSeqId::EMPTY;
2081        let mut cursor = prefix;
2082        while let Some(link) = self.diagnostic_link(cursor) {
2083            reversed = self.prepend_diagnostic_id(reversed, link.head);
2084            cursor = link.tail;
2085        }
2086        while let Some(link) = self.diagnostic_link(reversed) {
2087            suffix = self.prepend_diagnostic_id(suffix, link.head);
2088            reversed = link.tail;
2089        }
2090        suffix
2091    }
2092
2093    #[cfg(test)]
2094    fn diagnostic_sequence(
2095        &mut self,
2096        diagnostics: impl IntoIterator<Item = ParserDiagnostic>,
2097    ) -> DiagnosticSeqId {
2098        let diagnostics = diagnostics.into_iter().collect::<Vec<_>>();
2099        let mut sequence = DiagnosticSeqId::EMPTY;
2100        for diagnostic in diagnostics.into_iter().rev() {
2101            sequence = self.prepend_diagnostic(sequence, diagnostic);
2102        }
2103        sequence
2104    }
2105
2106    fn node(&self, id: RecognizedNodeId) -> ArenaRecognizedNode {
2107        self.nodes[id.0 as usize]
2108    }
2109
2110    fn set_boundary_alt_number(&mut self, id: RecognizedNodeId, alt_number: u32) {
2111        let ArenaRecognizedNode::LeftRecursiveBoundary {
2112            alt_number: stored, ..
2113        } = &mut self.nodes[id.0 as usize]
2114        else {
2115            unreachable!("deferred boundary must materialize as a boundary node");
2116        };
2117        *stored = alt_number;
2118    }
2119
2120    fn extra(&self, id: RecognitionExtraId) -> &RecognitionExtra {
2121        &self.extras[id.0 as usize]
2122    }
2123
2124    fn link(&self, id: NodeSeqId) -> Option<SeqLink> {
2125        (!id.is_empty()).then(|| self.seq_links[id.0 as usize])
2126    }
2127
2128    fn diagnostic_link(&self, id: DiagnosticSeqId) -> Option<DiagnosticLink> {
2129        (!id.is_empty()).then(|| self.diagnostic_links[id.0 as usize])
2130    }
2131
2132    const fn iter(&self, sequence: NodeSeqId) -> NodeSeqIter<'_> {
2133        NodeSeqIter {
2134            arena: self,
2135            cursor: sequence,
2136        }
2137    }
2138
2139    const fn diagnostics(&self, sequence: DiagnosticSeqId) -> DiagnosticSeqIter<'_> {
2140        DiagnosticSeqIter {
2141            arena: self,
2142            cursor: sequence,
2143        }
2144    }
2145
2146    fn diagnostics_len(&self, sequence: DiagnosticSeqId) -> usize {
2147        self.diagnostics(sequence).count()
2148    }
2149
2150    fn diagnostics_recovery_rank(&self, sequence: DiagnosticSeqId) -> usize {
2151        self.diagnostics(sequence)
2152            .filter(|diagnostic| {
2153                diagnostic.message.starts_with("mismatched input ")
2154                    && !diagnostic.message.starts_with("mismatched input '<EOF>' ")
2155            })
2156            .count()
2157    }
2158
2159    fn compare_diagnostics(&self, left: DiagnosticSeqId, right: DiagnosticSeqId) -> Ordering {
2160        self.diagnostics(left).cmp(self.diagnostics(right))
2161    }
2162
2163    fn sequence_len(&self, sequence: NodeSeqId) -> usize {
2164        self.iter(sequence).count()
2165    }
2166
2167    fn sequence_has_left_recursive_boundary(&self, sequence: NodeSeqId) -> bool {
2168        self.iter(sequence).any(|node| match self.node(node) {
2169            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
2170            ArenaRecognizedNode::Rule { children, .. } => {
2171                self.sequence_has_left_recursive_boundary(children)
2172            }
2173            ArenaRecognizedNode::Token { .. }
2174            | ArenaRecognizedNode::ErrorToken { .. }
2175            | ArenaRecognizedNode::MissingToken { .. } => false,
2176        })
2177    }
2178
2179    fn sequence_has_direct_boundary(&self, sequence: NodeSeqId) -> bool {
2180        self.iter(sequence).any(|node| {
2181            matches!(
2182                self.node(node),
2183                ArenaRecognizedNode::LeftRecursiveBoundary { .. }
2184            )
2185        })
2186    }
2187
2188    fn sequence_has_explicit_token(&self, sequence: NodeSeqId) -> bool {
2189        self.iter(sequence).any(|node| {
2190            matches!(
2191                self.node(node),
2192                ArenaRecognizedNode::Token { .. }
2193                    | ArenaRecognizedNode::ErrorToken { .. }
2194                    | ArenaRecognizedNode::MissingToken { .. }
2195            )
2196        })
2197    }
2198
2199    fn node_start_index(&self, node: RecognizedNodeId) -> Option<usize> {
2200        match self.node(node) {
2201            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
2202                Some(token.index())
2203            }
2204            ArenaRecognizedNode::MissingToken { extra } => {
2205                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
2206                    unreachable!("missing-token node must reference missing-token extra");
2207                };
2208                Some(*at_index as usize)
2209            }
2210            ArenaRecognizedNode::Rule { start_index, .. } => Some(start_index as usize),
2211            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
2212        }
2213    }
2214
2215    fn node_stop_index(&self, node: RecognizedNodeId) -> Option<usize> {
2216        match self.node(node) {
2217            ArenaRecognizedNode::Token { token } | ArenaRecognizedNode::ErrorToken { token } => {
2218                Some(token.index())
2219            }
2220            ArenaRecognizedNode::MissingToken { extra } => {
2221                let RecognitionExtra::MissingToken { at_index, .. } = self.extra(extra) else {
2222                    unreachable!("missing-token node must reference missing-token extra");
2223                };
2224                (*at_index as usize).checked_sub(1)
2225            }
2226            ArenaRecognizedNode::Rule { stop_index, .. } => stop_index.map(|index| index as usize),
2227            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => None,
2228        }
2229    }
2230
2231    fn node_span(&self, node: RecognizedNodeId) -> Option<(usize, Option<usize>)> {
2232        let start = self.node_start_index(node)?;
2233        let stop = self.node_stop_index(node);
2234        Some((start, stop))
2235    }
2236
2237    fn sequence_start_index(&self, sequence: NodeSeqId) -> Option<usize> {
2238        self.iter(sequence)
2239            .find_map(|node| self.node_start_index(node))
2240    }
2241
2242    fn sequence_stop_index(&self, sequence: NodeSeqId) -> Option<usize> {
2243        let mut stop = None;
2244        for node in self.iter(sequence) {
2245            if let Some(index) = self.node_stop_index(node) {
2246                stop = Some(index);
2247            }
2248        }
2249        stop
2250    }
2251
2252    fn sequence_needs_stable_tie(&self, sequence: NodeSeqId) -> bool {
2253        self.iter(sequence)
2254            .any(|node| self.node_needs_stable_tie(node))
2255    }
2256
2257    fn node_needs_stable_tie(&self, node: RecognizedNodeId) -> bool {
2258        match self.node(node) {
2259            ArenaRecognizedNode::Token { .. }
2260            | ArenaRecognizedNode::ErrorToken { .. }
2261            | ArenaRecognizedNode::MissingToken { .. } => false,
2262            ArenaRecognizedNode::LeftRecursiveBoundary { .. } => true,
2263            ArenaRecognizedNode::Rule {
2264                rule_index,
2265                children,
2266                ..
2267            } => self.iter(children).any(|child| {
2268                matches!(
2269                    self.node(child),
2270                    ArenaRecognizedNode::Rule {
2271                        rule_index: child_rule,
2272                        ..
2273                    } if child_rule == rule_index
2274                ) || self.node_needs_stable_tie(child)
2275            }),
2276        }
2277    }
2278
2279    fn compare_sequences(&self, mut left: NodeSeqId, mut right: NodeSeqId) -> Ordering {
2280        loop {
2281            match (self.link(left), self.link(right)) {
2282                (Some(left_link), Some(right_link)) => {
2283                    let order = self.compare_nodes(left_link.head, right_link.head);
2284                    if order != Ordering::Equal {
2285                        return order;
2286                    }
2287                    left = left_link.tail;
2288                    right = right_link.tail;
2289                }
2290                (None, None) => return Ordering::Equal,
2291                (None, Some(_)) => return Ordering::Less,
2292                (Some(_), None) => return Ordering::Greater,
2293            }
2294        }
2295    }
2296
2297    fn compare_nodes(&self, left: RecognizedNodeId, right: RecognizedNodeId) -> Ordering {
2298        let left = self.node(left);
2299        let right = self.node(right);
2300        match (left, right) {
2301            (
2302                ArenaRecognizedNode::Token { token: left },
2303                ArenaRecognizedNode::Token { token: right },
2304            )
2305            | (
2306                ArenaRecognizedNode::ErrorToken { token: left },
2307                ArenaRecognizedNode::ErrorToken { token: right },
2308            ) => left.cmp(&right),
2309            (
2310                ArenaRecognizedNode::MissingToken { extra: left },
2311                ArenaRecognizedNode::MissingToken { extra: right },
2312            ) => self.extra(left).cmp(self.extra(right)),
2313            (
2314                ArenaRecognizedNode::Rule {
2315                    rule_index: left_rule,
2316                    invoking_state: left_invoking,
2317                    alt_number: left_alt,
2318                    start_index: left_start,
2319                    stop_index: left_stop,
2320                    return_values: left_returns,
2321                    children: left_children,
2322                },
2323                ArenaRecognizedNode::Rule {
2324                    rule_index: right_rule,
2325                    invoking_state: right_invoking,
2326                    alt_number: right_alt,
2327                    start_index: right_start,
2328                    stop_index: right_stop,
2329                    return_values: right_returns,
2330                    children: right_children,
2331                },
2332            ) => (left_rule, left_invoking, left_alt, left_start, left_stop)
2333                .cmp(&(
2334                    right_rule,
2335                    right_invoking,
2336                    right_alt,
2337                    right_start,
2338                    right_stop,
2339                ))
2340                .then_with(|| {
2341                    left_returns
2342                        .map(|id| self.extra(id))
2343                        .cmp(&right_returns.map(|id| self.extra(id)))
2344                })
2345                .then_with(|| self.compare_sequences(left_children, right_children)),
2346            (
2347                ArenaRecognizedNode::LeftRecursiveBoundary {
2348                    rule_index: left_rule,
2349                    alt_number: left_alt,
2350                },
2351                ArenaRecognizedNode::LeftRecursiveBoundary {
2352                    rule_index: right_rule,
2353                    alt_number: right_alt,
2354                },
2355            ) => (left_rule, left_alt).cmp(&(right_rule, right_alt)),
2356            (left, right) => recognition_node_kind(&left).cmp(&recognition_node_kind(&right)),
2357        }
2358    }
2359
2360    fn reverse_sequence(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
2361        let mut reversed = NodeSeqId::EMPTY;
2362        while let Some(link) = self.link(sequence) {
2363            reversed = self.prepend(reversed, link.head);
2364            sequence = link.tail;
2365        }
2366        reversed
2367    }
2368
2369    fn fold_left_recursive_boundaries(&mut self, mut sequence: NodeSeqId) -> NodeSeqId {
2370        if !self.sequence_has_direct_boundary(sequence) {
2371            return sequence;
2372        }
2373        let mut reversed = NodeSeqId::EMPTY;
2374        while let Some(link) = self.link(sequence) {
2375            match self.node(link.head) {
2376                ArenaRecognizedNode::LeftRecursiveBoundary {
2377                    rule_index,
2378                    alt_number,
2379                } => {
2380                    if !reversed.is_empty() {
2381                        let children = self.reverse_sequence(reversed);
2382                        let start_index = self.sequence_start_index(children).unwrap_or_default();
2383                        let stop_index = self.sequence_stop_index(children);
2384                        let rule = self.push_node(ArenaRecognizedNode::Rule {
2385                            rule_index,
2386                            invoking_state: -1,
2387                            alt_number,
2388                            start_index: u32::try_from(start_index)
2389                                .expect("left-recursive start index fits in u32"),
2390                            stop_index: stop_index.map(|index| {
2391                                u32::try_from(index).expect("left-recursive stop index fits in u32")
2392                            }),
2393                            return_values: None,
2394                            children,
2395                        });
2396                        reversed = self.prepend(NodeSeqId::EMPTY, rule);
2397                    }
2398                }
2399                _ => {
2400                    reversed = self.prepend(reversed, link.head);
2401                }
2402            }
2403            sequence = link.tail;
2404        }
2405        self.reverse_sequence(reversed)
2406    }
2407
2408    fn stats(&self, root: NodeSeqId, diagnostics: DiagnosticSeqId) -> RecognitionArenaStats {
2409        let mut live_nodes = vec![false; self.nodes.len()];
2410        let mut live_links = vec![false; self.seq_links.len()];
2411        let mut live_diagnostic_links = vec![false; self.diagnostic_links.len()];
2412        let mut live_extras = vec![false; self.extras.len()];
2413        let mut pending = vec![root];
2414        while let Some(mut sequence) = pending.pop() {
2415            while let Some(link) = self.link(sequence) {
2416                let link_index = sequence.0 as usize;
2417                if live_links[link_index] {
2418                    break;
2419                }
2420                live_links[link_index] = true;
2421                let node_index = link.head.0 as usize;
2422                if !live_nodes[node_index] {
2423                    live_nodes[node_index] = true;
2424                    match self.node(link.head) {
2425                        ArenaRecognizedNode::MissingToken { extra } => {
2426                            live_extras[extra.0 as usize] = true;
2427                        }
2428                        ArenaRecognizedNode::Rule {
2429                            return_values,
2430                            children,
2431                            ..
2432                        } => {
2433                            if let Some(extra) = return_values {
2434                                live_extras[extra.0 as usize] = true;
2435                            }
2436                            pending.push(children);
2437                        }
2438                        ArenaRecognizedNode::Token { .. }
2439                        | ArenaRecognizedNode::ErrorToken { .. }
2440                        | ArenaRecognizedNode::LeftRecursiveBoundary { .. } => {}
2441                    }
2442                }
2443                sequence = link.tail;
2444            }
2445        }
2446        let mut diagnostics = diagnostics;
2447        while let Some(link) = self.diagnostic_link(diagnostics) {
2448            let link_index = diagnostics.0 as usize;
2449            if live_diagnostic_links[link_index] {
2450                break;
2451            }
2452            live_diagnostic_links[link_index] = true;
2453            live_extras[link.head.0 as usize] = true;
2454            diagnostics = link.tail;
2455        }
2456        let live_node_count = live_nodes.into_iter().filter(|live| *live).count();
2457        let live_link_count = live_links.into_iter().filter(|live| *live).count()
2458            + live_diagnostic_links
2459                .into_iter()
2460                .filter(|live| *live)
2461                .count();
2462        let live_extra_count = live_extras.into_iter().filter(|live| *live).count();
2463        let total_links = self.seq_links.len() + self.diagnostic_links.len();
2464        RecognitionArenaStats {
2465            total_nodes: self.nodes.len(),
2466            live_nodes: live_node_count,
2467            dead_nodes: self.nodes.len().saturating_sub(live_node_count),
2468            node_capacity: self.nodes.capacity(),
2469            total_links,
2470            live_links: live_link_count,
2471            dead_links: total_links.saturating_sub(live_link_count),
2472            link_capacity: self.seq_links.capacity() + self.diagnostic_links.capacity(),
2473            total_extras: self.extras.len(),
2474            live_extras: live_extra_count,
2475            dead_extras: self.extras.len().saturating_sub(live_extra_count),
2476            extra_capacity: self.extras.capacity(),
2477        }
2478    }
2479}
2480
2481fn reset_arena_vec<T>(storage: &mut Vec<T>, max_retained_capacity: usize) {
2482    if storage.capacity() > max_retained_capacity {
2483        *storage = Vec::new();
2484    } else {
2485        storage.clear();
2486    }
2487}
2488
2489const fn recognition_node_kind(node: &ArenaRecognizedNode) -> u8 {
2490    match node {
2491        ArenaRecognizedNode::Token { .. } => 0,
2492        ArenaRecognizedNode::ErrorToken { .. } => 1,
2493        ArenaRecognizedNode::MissingToken { .. } => 2,
2494        ArenaRecognizedNode::Rule { .. } => 3,
2495        ArenaRecognizedNode::LeftRecursiveBoundary { .. } => 4,
2496    }
2497}
2498
2499struct NodeSeqIter<'a> {
2500    arena: &'a RecognitionArena,
2501    cursor: NodeSeqId,
2502}
2503
2504impl Iterator for NodeSeqIter<'_> {
2505    type Item = RecognizedNodeId;
2506
2507    fn next(&mut self) -> Option<Self::Item> {
2508        let link = self.arena.link(self.cursor)?;
2509        self.cursor = link.tail;
2510        Some(link.head)
2511    }
2512}
2513
2514struct DiagnosticSeqIter<'a> {
2515    arena: &'a RecognitionArena,
2516    cursor: DiagnosticSeqId,
2517}
2518
2519impl<'a> Iterator for DiagnosticSeqIter<'a> {
2520    type Item = &'a ParserDiagnostic;
2521
2522    fn next(&mut self) -> Option<Self::Item> {
2523        let link = self.arena.diagnostic_link(self.cursor)?;
2524        self.cursor = link.tail;
2525        let RecognitionExtra::Diagnostic(diagnostic) = self.arena.extra(link.head) else {
2526            unreachable!("diagnostic link must reference diagnostic extra");
2527        };
2528        Some(diagnostic)
2529    }
2530}
2531
2532#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
2533struct ParserDiagnostic {
2534    line: usize,
2535    column: usize,
2536    message: String,
2537    /// Token the diagnostic is anchored to, resolved to a view when the
2538    /// diagnostic is dispatched to error listeners. `None` when no token
2539    /// exists (synthetic positions, lexer-originated messages).
2540    offending: Option<TokenId>,
2541}
2542
2543#[derive(Clone, Debug, Default, Eq, PartialEq)]
2544struct ExpectedTokens {
2545    index: Option<usize>,
2546    symbols: BTreeSet<i32>,
2547    no_viable: Option<NoViableAlternative>,
2548}
2549
2550#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2551struct NoViableAlternative {
2552    start_index: usize,
2553    error_index: usize,
2554}
2555
2556impl ExpectedTokens {
2557    /// Records the expected symbols for the farthest token index reached by any
2558    /// failed ATN path.
2559    fn record_transition(
2560        &mut self,
2561        index: usize,
2562        transition: ParserTransition<'_>,
2563        max_token_type: i32,
2564    ) {
2565        let symbols = transition_expected_symbols(transition, max_token_type);
2566        match self.index {
2567            Some(current) if index < current => {}
2568            Some(current) if index == current => self.symbols.extend(symbols),
2569            _ => {
2570                self.index = Some(index);
2571                self.symbols = symbols;
2572            }
2573        }
2574    }
2575
2576    /// Records an ambiguous decision that failed after consuming a shared
2577    /// prefix, which ANTLR reports as `no viable alternative`.
2578    const fn record_no_viable(&mut self, start_index: usize, error_index: usize) {
2579        match self.no_viable {
2580            Some(current) if error_index < current.error_index => {}
2581            _ => {
2582                self.no_viable = Some(NoViableAlternative {
2583                    start_index,
2584                    error_index,
2585                });
2586            }
2587        }
2588    }
2589}
2590
2591/// Compact token-type set for parser-internal FIRST/lookahead caches.
2592///
2593/// Public diagnostics still use `BTreeSet<i32>` for deterministic formatting,
2594/// but the hot recognizer path mostly needs `contains` and set union over
2595/// small token ids. A bitset avoids tree traversal and per-symbol allocation
2596/// while keeping conversion to `BTreeSet` at recovery/reporting boundaries.
2597#[derive(Clone, Debug, Default, Eq, PartialEq)]
2598struct TokenBitSet {
2599    words: Vec<u64>,
2600}
2601
2602impl TokenBitSet {
2603    fn insert(&mut self, symbol: i32) {
2604        let Some(slot) = token_bit_slot(symbol) else {
2605            return;
2606        };
2607        let word = slot / u64::BITS as usize;
2608        if word >= self.words.len() {
2609            self.words.resize(word + 1, 0);
2610        }
2611        self.words[word] |= 1_u64 << (slot % u64::BITS as usize);
2612    }
2613
2614    fn extend_range(&mut self, start: i32, stop: i32) {
2615        let (start, stop) = if start <= stop {
2616            (start, stop)
2617        } else {
2618            (stop, start)
2619        };
2620        if start <= TOKEN_EOF && stop >= TOKEN_EOF {
2621            self.insert(TOKEN_EOF);
2622        }
2623        let positive_start = start.max(1);
2624        if positive_start > stop {
2625            return;
2626        }
2627        let Some(start_slot) = token_bit_slot(positive_start) else {
2628            return;
2629        };
2630        let Some(stop_slot) = token_bit_slot(stop) else {
2631            return;
2632        };
2633        self.extend_slot_range(start_slot, stop_slot);
2634    }
2635
2636    fn extend_slot_range(&mut self, start_slot: usize, stop_slot: usize) {
2637        if start_slot > stop_slot {
2638            return;
2639        }
2640        let start_word = start_slot / u64::BITS as usize;
2641        let stop_word = stop_slot / u64::BITS as usize;
2642        if stop_word >= self.words.len() {
2643            self.words.resize(stop_word + 1, 0);
2644        }
2645        let start_offset = start_slot % u64::BITS as usize;
2646        let stop_offset = stop_slot % u64::BITS as usize;
2647        if start_word == stop_word {
2648            self.words[start_word] |=
2649                (!0_u64 << start_offset) & (!0_u64 >> (u64::BITS as usize - 1 - stop_offset));
2650            return;
2651        }
2652        self.words[start_word] |= !0_u64 << start_offset;
2653        for word in &mut self.words[(start_word + 1)..stop_word] {
2654            *word = !0_u64;
2655        }
2656        self.words[stop_word] |= !0_u64 >> (u64::BITS as usize - 1 - stop_offset);
2657    }
2658
2659    fn extend_iter(&mut self, symbols: impl IntoIterator<Item = i32>) {
2660        for symbol in symbols {
2661            self.insert(symbol);
2662        }
2663    }
2664
2665    fn extend_from(&mut self, other: &Self) {
2666        if other.words.len() > self.words.len() {
2667            self.words.resize(other.words.len(), 0);
2668        }
2669        for (left, right) in self.words.iter_mut().zip(&other.words) {
2670            *left |= *right;
2671        }
2672    }
2673
2674    fn contains(&self, symbol: i32) -> bool {
2675        let Some(slot) = token_bit_slot(symbol) else {
2676            return false;
2677        };
2678        let word = slot / u64::BITS as usize;
2679        self.words
2680            .get(word)
2681            .is_some_and(|bits| bits & (1_u64 << (slot % u64::BITS as usize)) != 0)
2682    }
2683
2684    fn is_empty(&self) -> bool {
2685        self.words.iter().all(|word| *word == 0)
2686    }
2687
2688    fn symbols(&self) -> impl Iterator<Item = i32> + '_ {
2689        self.words
2690            .iter()
2691            .copied()
2692            .enumerate()
2693            .flat_map(|(word_index, mut bits)| {
2694                std::iter::from_fn(move || {
2695                    while bits != 0 {
2696                        let bit = bits.trailing_zeros() as usize;
2697                        bits &= bits - 1;
2698                        if let Some(symbol) =
2699                            token_bit_symbol(word_index * u64::BITS as usize + bit)
2700                        {
2701                            return Some(symbol);
2702                        }
2703                    }
2704                    None
2705                })
2706            })
2707    }
2708
2709    fn extend_btree_set(&self, target: &mut BTreeSet<i32>) {
2710        target.extend(self.symbols());
2711    }
2712
2713    fn to_btree_set(&self) -> BTreeSet<i32> {
2714        let mut out = BTreeSet::new();
2715        self.extend_btree_set(&mut out);
2716        out
2717    }
2718}
2719
2720fn token_bit_slot(symbol: i32) -> Option<usize> {
2721    if symbol == TOKEN_EOF {
2722        Some(0)
2723    } else if symbol > 0 {
2724        usize::try_from(symbol).ok()
2725    } else {
2726        None
2727    }
2728}
2729
2730fn token_bit_symbol(slot: usize) -> Option<i32> {
2731    if slot == 0 {
2732        Some(TOKEN_EOF)
2733    } else {
2734        i32::try_from(slot).ok()
2735    }
2736}
2737
2738/// Converts one consuming transition into the token types that would satisfy it
2739/// for diagnostic reporting.
2740fn transition_expected_symbols(
2741    transition: ParserTransition<'_>,
2742    max_token_type: i32,
2743) -> BTreeSet<i32> {
2744    let mut symbols = BTreeSet::new();
2745    match &transition.data() {
2746        Transition::Atom { label, .. } => {
2747            symbols.insert(*label);
2748        }
2749        Transition::Range { start, stop, .. } => {
2750            symbols.extend(*start..=*stop);
2751        }
2752        Transition::Set { set, .. } => {
2753            for (start, stop) in set.ranges() {
2754                symbols.extend(start..=stop);
2755            }
2756        }
2757        Transition::NotSet { set, .. } => {
2758            symbols.extend((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2759        }
2760        Transition::Wildcard { .. } => {
2761            symbols.extend(1..=max_token_type);
2762        }
2763        Transition::Epsilon { .. }
2764        | Transition::Rule { .. }
2765        | Transition::Predicate { .. }
2766        | Transition::Action { .. }
2767        | Transition::Precedence { .. } => {}
2768    }
2769    symbols
2770}
2771
2772fn transition_expected_token_set(
2773    transition: ParserTransition<'_>,
2774    max_token_type: i32,
2775) -> TokenBitSet {
2776    let mut symbols = TokenBitSet::default();
2777    match &transition.data() {
2778        Transition::Atom { label, .. } => {
2779            symbols.insert(*label);
2780        }
2781        Transition::Range { start, stop, .. } => {
2782            symbols.extend_range(*start, *stop);
2783        }
2784        Transition::Set { set, .. } => {
2785            for (start, stop) in set.ranges() {
2786                symbols.extend_range(start, stop);
2787            }
2788        }
2789        Transition::NotSet { set, .. } => {
2790            symbols.extend_iter((1..=max_token_type).filter(|symbol| !set.contains(*symbol)));
2791        }
2792        Transition::Wildcard { .. } => {
2793            symbols.extend_range(1, max_token_type);
2794        }
2795        Transition::Epsilon { .. }
2796        | Transition::Rule { .. }
2797        | Transition::Predicate { .. }
2798        | Transition::Action { .. }
2799        | Transition::Precedence { .. } => {}
2800    }
2801    symbols
2802}
2803
2804/// Returns the consuming-token expectations reachable from an ATN state through
2805/// epsilon transitions. Recovery diagnostics need this closure so alternatives
2806/// and loop exits report the same expectation set ANTLR users see.
2807fn state_expected_symbols(atn: &Atn, state_number: usize) -> BTreeSet<i32> {
2808    let mut symbols = BTreeSet::new();
2809    let mut stack = vec![state_number];
2810    let mut visited = BTreeSet::new();
2811    while let Some(current) = stack.pop() {
2812        if !visited.insert(current) {
2813            continue;
2814        }
2815        let Some(state) = atn.state(current) else {
2816            continue;
2817        };
2818        for transition in &state.transitions() {
2819            let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
2820            if transition_symbols.is_empty() {
2821                if transition.is_epsilon() {
2822                    stack.push(transition.target());
2823                }
2824            } else {
2825                symbols.extend(transition_symbols);
2826            }
2827        }
2828    }
2829    symbols
2830}
2831
2832fn state_expected_token_set(atn: &Atn, state_number: usize) -> TokenBitSet {
2833    let mut symbols = TokenBitSet::default();
2834    let mut stack = vec![state_number];
2835    let mut visited = BTreeSet::new();
2836    while let Some(current) = stack.pop() {
2837        if !visited.insert(current) {
2838            continue;
2839        }
2840        let Some(state) = atn.state(current) else {
2841            continue;
2842        };
2843        for transition in &state.transitions() {
2844            let transition_symbols =
2845                transition_expected_token_set(transition, atn.max_token_type());
2846            if transition_symbols.is_empty() {
2847                if transition.is_epsilon() {
2848                    stack.push(transition.target());
2849                }
2850            } else {
2851                symbols.extend_from(&transition_symbols);
2852            }
2853        }
2854    }
2855    symbols
2856}
2857
2858fn state_can_reach_rule_stop(atn: &Atn, state_number: usize) -> bool {
2859    let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
2860        return false;
2861    };
2862    let Some(stop_state) = atn.rule_to_stop_state().get(rule_index) else {
2863        return false;
2864    };
2865    epsilon_reaches_state(atn, state_number, stop_state)
2866}
2867
2868fn epsilon_reaches_state(atn: &Atn, start: usize, target: usize) -> bool {
2869    let mut stack = vec![start];
2870    let mut visited = BTreeSet::new();
2871    while let Some(current) = stack.pop() {
2872        if current == target {
2873            return true;
2874        }
2875        if !visited.insert(current) {
2876            continue;
2877        }
2878        let Some(state) = atn.state(current) else {
2879            continue;
2880        };
2881        stack.extend(
2882            state
2883                .transitions()
2884                .iter()
2885                .filter(|transition| transition.is_epsilon())
2886                .map(ParserTransition::target),
2887        );
2888    }
2889    false
2890}
2891
2892/// FIRST set for a rule entry plus whether the rule is nullable.
2893///
2894/// Walks epsilon, predicate, action, and rule-call transitions until it finds
2895/// a consuming transition or reaches the rule's stop state. Used by the fast
2896/// recognizer to skip rule alternatives whose first-consumed token cannot
2897/// possibly match the current lookahead.
2898#[derive(Clone, Debug, Default, Eq, PartialEq)]
2899struct FirstSet {
2900    symbols: TokenBitSet,
2901    nullable: bool,
2902}
2903
2904/// Per-parser cache of FIRST sets computed during recognition. The fast path
2905/// consults this on every speculative `Transition::Rule` encounter, so the
2906/// computation must amortize across all of those calls — the FIRST set is a
2907/// pure function of the ATN, not of the input position. Cached entries are
2908/// shared via `Rc` so the recognizer never deep-copies the underlying
2909/// `BTreeSet<i32>`.
2910type FirstSetCache = FxHashMap<(usize, usize), Rc<FirstSet>>;
2911
2912// Thread-local FIRST-set caches keyed by the ATN pointer. The FIRST set
2913// and decision-lookahead entries are purely functions of the grammar's
2914// ATN, so caching across parses lets repeated parsing of the same grammar
2915// (the common case for a CLI tool or language server) avoid redoing the
2916// closure work. Generated parsers hand us a `&'static Atn` whose address
2917// is stable, which is what we hash on.
2918type DecisionLookaheadCache = FxHashMap<usize, Rc<DecisionLookahead>>;
2919
2920#[derive(Debug, Default)]
2921struct LeftRecursiveOperatorLookahead {
2922    /// Operator alts whose token-prefix is fully matched by this one symbol
2923    /// (then only epsilons/actions remain before the recursive RHS call).
2924    /// Safe for one-token loop-enter fast path.
2925    single_token: TokenBitSet,
2926    /// Operator alts that start with this symbol but still require more tokens
2927    /// before the operand. Must not force enter from one-token lookahead when a
2928    /// shorter operator shares the prefix; `StarLoopEntry` adaptive prediction
2929    /// has to weigh the exit alt as well.
2930    multi_token_prefix: TokenBitSet,
2931    predicate_dependent: TokenBitSet,
2932}
2933
2934#[derive(Default)]
2935struct SharedAtnCache {
2936    first_set: FirstSetCache,
2937    decision_lookahead: DecisionLookaheadCache,
2938    left_recursive_operator_lookahead: FxHashMap<(usize, i32), Rc<LeftRecursiveOperatorLookahead>>,
2939    state_before_stop_lookahead: FxHashMap<(usize, usize), Rc<StateBeforeStopLookahead>>,
2940    state_expected_tokens: FxHashMap<usize, Rc<TokenBitSet>>,
2941    rule_stop_reach: FxHashMap<usize, bool>,
2942    observable_action_transitions: Option<bool>,
2943    predicate_transitions: Option<bool>,
2944}
2945
2946thread_local! {
2947    static SHARED_ATN_CACHES: RefCell<FxHashMap<SharedAtnCacheKey, SharedAtnCache>> =
2948        RefCell::new(FxHashMap::default());
2949}
2950
2951/// Compound key for `SHARED_ATN_CACHES`.
2952///
2953/// Generated parsers feed us a `&'static Atn` from a `OnceLock<Atn>`, so the
2954/// pointer identifies one grammar for the program's lifetime. For the
2955/// non-`'static` case (a dropped `Atn` whose allocation is later reused),
2956/// the secondary fields below catch the pointer collision: a new grammar
2957/// would need to match all of `(states ptr, states len, max_token_type)` to
2958/// be mistaken for the dropped one. That combination changing under us
2959/// without a rebuild is implausible enough to treat as a bug; bundling them
2960/// into the key is otherwise a few extra bytes per lookup.
2961#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2962struct SharedAtnCacheKey {
2963    atn: usize,
2964    states: usize,
2965    state_count: usize,
2966    max_token_type: i32,
2967}
2968
2969impl SharedAtnCacheKey {
2970    fn for_atn(atn: &Atn) -> Self {
2971        let (states, state_count) = atn.storage_identity();
2972        Self {
2973            atn: std::ptr::from_ref::<Atn>(atn) as usize,
2974            states,
2975            state_count,
2976            max_token_type: atn.max_token_type(),
2977        }
2978    }
2979}
2980
2981fn with_shared_first_set_cache<R>(atn: &Atn, f: impl FnOnce(&mut FirstSetCache) -> R) -> R {
2982    SHARED_ATN_CACHES.with(|cell| {
2983        let key = SharedAtnCacheKey::for_atn(atn);
2984        let mut map = cell.borrow_mut();
2985        let cache = map.entry(key).or_default();
2986        f(&mut cache.first_set)
2987    })
2988}
2989
2990fn with_shared_atn_caches<R>(atn: &Atn, f: impl FnOnce(&mut SharedAtnCache) -> R) -> R {
2991    SHARED_ATN_CACHES.with(|cell| {
2992        let key = SharedAtnCacheKey::for_atn(atn);
2993        let mut map = cell.borrow_mut();
2994        let cache = map.entry(key).or_default();
2995        f(cache)
2996    })
2997}
2998
2999/// Per-decision-state cached look-1 sets for each outgoing transition.
3000///
3001/// At a multi-alternative state, the recognizer would otherwise speculatively
3002/// walk every alternative even when only one can possibly accept the current
3003/// lookahead. Caching the look-1 set per transition lets us prune the
3004/// non-viable transitions before recursing — the same SLL prediction trick
3005/// the reference ANTLR runtime uses, just expressed as a `(state, lookahead)`
3006/// filter rather than a full DFA.
3007#[derive(Debug, Default)]
3008struct DecisionLookahead {
3009    transitions: Vec<TransitionLookSet>,
3010}
3011
3012/// Look-1 information for one outgoing transition.
3013///
3014/// `nullable` mirrors `FirstSet::nullable` and is true when the transition
3015/// can reach the rule stop without consuming a token (e.g. an empty alt).
3016/// Nullable transitions cannot be pruned: they may still be the right path
3017/// when the lookahead consumes nothing further inside the current rule.
3018#[derive(Clone, Debug, Default)]
3019struct TransitionLookSet {
3020    symbols: TokenBitSet,
3021    nullable: bool,
3022}
3023
3024/// Mutable bookkeeping shared across one FIRST-set computation. Bundling the
3025/// rarely-touched fields keeps the recursive helpers below the function-arity
3026/// lint and lets every nested call thread the same cache and cycle guards.
3027struct FirstSetCtx<'a> {
3028    cache: &'a mut FirstSetCache,
3029    in_progress: BTreeSet<(usize, usize)>,
3030    hit_cycle: bool,
3031}
3032
3033/// Returns the FIRST set for the (rule entry, rule stop) pair, populating the
3034/// shared cache and tolerating recursive nullable rule chains. Mutually
3035/// recursive rules cannot stack-overflow because callers in flight are tracked
3036/// in `ctx.in_progress`; revisits return without recursing, and the partial
3037/// result is cached only when no cycle was detected during its computation.
3038///
3039/// On a cache hit the returned `Rc` is shared with the recognizer so subsequent
3040/// rule-call probes only pay a reference bump.
3041fn rule_first_set(
3042    atn: &Atn,
3043    target: usize,
3044    rule_stop_state: usize,
3045    cache: &mut FirstSetCache,
3046) -> Rc<FirstSet> {
3047    if let Some(cached) = cache.get(&(target, rule_stop_state)) {
3048        return Rc::clone(cached);
3049    }
3050    let mut ctx = FirstSetCtx {
3051        cache,
3052        in_progress: BTreeSet::new(),
3053        hit_cycle: false,
3054    };
3055    rule_first_set_cached(atn, target, rule_stop_state, &mut ctx)
3056}
3057
3058fn rule_first_set_cached(
3059    atn: &Atn,
3060    target: usize,
3061    rule_stop_state: usize,
3062    ctx: &mut FirstSetCtx<'_>,
3063) -> Rc<FirstSet> {
3064    let key = (target, rule_stop_state);
3065    if let Some(cached) = ctx.cache.get(&key) {
3066        return Rc::clone(cached);
3067    }
3068    if !ctx.in_progress.insert(key) {
3069        // Cycle: a caller above is already computing this entry. Return an
3070        // empty FIRST set; that caller's traversal supplies the contributions
3071        // from the rule's other alternatives.
3072        return Rc::new(FirstSet::default());
3073    }
3074    let saved_hit_cycle = ctx.hit_cycle;
3075    ctx.hit_cycle = false;
3076    let mut first = FirstSet::default();
3077    let mut visited = BTreeSet::new();
3078    rule_first_set_inner(atn, target, rule_stop_state, ctx, &mut visited, &mut first);
3079    ctx.in_progress.remove(&key);
3080    let entry = Rc::new(first);
3081    if !ctx.hit_cycle {
3082        ctx.cache.insert(key, Rc::clone(&entry));
3083    }
3084    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
3085    entry
3086}
3087
3088/// Returns the look-1 set for traversing `transition` while still inside the
3089/// current `rule_stop_state`. Used by the multi-alternative prefilter, which
3090/// prunes transitions whose look-1 cannot accept the current lookahead.
3091fn transition_first_set(
3092    atn: &Atn,
3093    transition: ParserTransition<'_>,
3094    rule_stop_state: usize,
3095    cache: &mut FirstSetCache,
3096) -> TransitionLookSet {
3097    match &transition.data() {
3098        Transition::Atom { label, .. } => {
3099            let mut symbols = TokenBitSet::default();
3100            symbols.insert(*label);
3101            TransitionLookSet {
3102                symbols,
3103                nullable: false,
3104            }
3105        }
3106        Transition::Range { start, stop, .. } => {
3107            let mut symbols = TokenBitSet::default();
3108            symbols.extend_range(*start, *stop);
3109            TransitionLookSet {
3110                symbols,
3111                nullable: false,
3112            }
3113        }
3114        Transition::Set { set, .. } => {
3115            let mut symbols = TokenBitSet::default();
3116            for (start, stop) in set.ranges() {
3117                symbols.extend_range(start, stop);
3118            }
3119            TransitionLookSet {
3120                symbols,
3121                nullable: false,
3122            }
3123        }
3124        Transition::NotSet { set, .. } => {
3125            let max = atn.max_token_type();
3126            let mut symbols = TokenBitSet::default();
3127            symbols.extend_iter((1..=max).filter(|symbol| !set.contains(*symbol)));
3128            TransitionLookSet {
3129                symbols,
3130                nullable: false,
3131            }
3132        }
3133        Transition::Wildcard { .. } => {
3134            let mut symbols = TokenBitSet::default();
3135            symbols.extend_range(1, atn.max_token_type());
3136            TransitionLookSet {
3137                symbols,
3138                nullable: false,
3139            }
3140        }
3141        Transition::Epsilon { target }
3142        | Transition::Action { target, .. }
3143        | Transition::Predicate { target, .. }
3144        | Transition::Precedence { target, .. } => {
3145            // Walk the closure starting at `target` until a consuming transition
3146            // is reached or the rule stop state is hit.
3147            let first = rule_first_set(atn, *target, rule_stop_state, cache);
3148            TransitionLookSet {
3149                symbols: first.symbols.clone(),
3150                nullable: first.nullable,
3151            }
3152        }
3153        Transition::Rule {
3154            target,
3155            rule_index,
3156            follow_state,
3157            ..
3158        } => {
3159            let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3160                return TransitionLookSet::default();
3161            };
3162            let child = rule_first_set(atn, *target, child_stop, cache);
3163            let mut symbols = child.symbols.clone();
3164            let nullable = if child.nullable {
3165                let follow = rule_first_set(atn, *follow_state, rule_stop_state, cache);
3166                symbols.extend_from(&follow.symbols);
3167                follow.nullable
3168            } else {
3169                false
3170            };
3171            TransitionLookSet { symbols, nullable }
3172        }
3173    }
3174}
3175
3176/// Reports whether `transition` can be pruned at a multi-alt state because
3177/// its cached look-1 cannot accept the current lookahead.
3178///
3179/// Pruning runs only for non-consuming transitions (Epsilon/Action/Predicate/
3180/// Rule/Precedence) so consuming transitions still reach the
3181/// `matches`+recovery path that surfaces single-token deletion / insertion
3182/// repairs and ANTLR-compatible expected-token sets. When a non-consuming
3183/// transition is pruned, its FIRST set is folded into `expected` so failed
3184/// parses produce the same `mismatched input ... expecting ...` diagnostic
3185/// the no-prefilter baseline would emit.
3186/// Returns the unique alt index (0-based) when `symbol` falls into exactly
3187/// one transition's FIRST set and no transition is nullable. Used as an
3188/// LL(1) commit point: when prediction is unambiguous from the lookahead
3189/// alone, the recursive recognizer can skip every other alt without paying
3190/// for the per-transition filter probe.
3191///
3192/// `None` signals the caller to fall back to per-transition lookahead
3193/// filtering. Returning `Some` for an alt whose transition cannot actually
3194/// match would prune the only viable parse path; this is why we require
3195/// strict disjointness *and* no nullable transitions in the decision.
3196fn ll1_unique_alt(entry: &DecisionLookahead, symbol: i32) -> Option<usize> {
3197    let mut chosen: Option<usize> = None;
3198    for (index, transition) in entry.transitions.iter().enumerate() {
3199        if transition.nullable {
3200            return None;
3201        }
3202        if transition.symbols.contains(symbol) {
3203            if chosen.is_some() {
3204                return None;
3205            }
3206            chosen = Some(index);
3207        }
3208    }
3209    chosen
3210}
3211
3212/// Returns the unique greedy alt index (0-based) selected by the current
3213/// lookahead.
3214///
3215/// The shortcut is intentionally conservative around nullable exits. If the
3216/// current symbol can start a consuming alternative and an empty alternative is
3217/// also present, one-token lookahead is not enough to know whether the symbol
3218/// belongs to the current construct or to its caller's follow set. `None`
3219/// signals the caller to fall back to adaptive prediction.
3220fn ll1_greedy_alt(entry: &DecisionLookahead, symbol: i32, non_greedy: bool) -> Option<usize> {
3221    let mut matching_non_nullable_alt = None;
3222    let mut nullable_alt = None;
3223    for (index, transition) in entry.transitions.iter().enumerate() {
3224        if transition.nullable {
3225            if nullable_alt.is_some() {
3226                return None;
3227            }
3228            nullable_alt = Some(index);
3229        }
3230        if transition.symbols.contains(symbol) {
3231            if transition.nullable {
3232                continue;
3233            }
3234            if matching_non_nullable_alt.is_some() {
3235                return None;
3236            }
3237            matching_non_nullable_alt = Some(index);
3238        }
3239    }
3240    if matching_non_nullable_alt.is_some() && nullable_alt.is_some() {
3241        return None;
3242    }
3243    if non_greedy {
3244        nullable_alt.or(matching_non_nullable_alt)
3245    } else {
3246        matching_non_nullable_alt.or(nullable_alt)
3247    }
3248}
3249
3250fn should_skip_via_lookahead(
3251    transition_kind: ParserTransitionKind,
3252    transition_index: usize,
3253    lookahead_filter: Option<&(i32, Rc<DecisionLookahead>)>,
3254    index: usize,
3255    record_expected: bool,
3256    expected: &mut ExpectedTokens,
3257) -> bool {
3258    let prune_non_consuming = matches!(
3259        transition_kind,
3260        ParserTransitionKind::Epsilon
3261            | ParserTransitionKind::Action
3262            | ParserTransitionKind::Predicate
3263            | ParserTransitionKind::Rule
3264            | ParserTransitionKind::Precedence
3265    );
3266    if !prune_non_consuming {
3267        return false;
3268    }
3269    let Some((symbol, entry)) = lookahead_filter else {
3270        return false;
3271    };
3272    let Some(set) = entry.transitions.get(transition_index) else {
3273        return false;
3274    };
3275    if set.symbols.contains(*symbol) || set.nullable {
3276        return false;
3277    }
3278    if record_expected && !set.symbols.is_empty() {
3279        record_pruned_transition_expected(set, index, expected);
3280    }
3281    true
3282}
3283
3284fn should_skip_rule_via_first_set(
3285    first: &FirstSet,
3286    symbol: i32,
3287    record_expected: bool,
3288    index: usize,
3289    expected: &mut ExpectedTokens,
3290) -> bool {
3291    if first.nullable || first.symbols.contains(symbol) {
3292        return false;
3293    }
3294    if record_expected && !first.symbols.is_empty() {
3295        record_token_bit_expected(&first.symbols, index, expected);
3296    }
3297    true
3298}
3299
3300fn record_token_bit_expected(symbols: &TokenBitSet, index: usize, expected: &mut ExpectedTokens) {
3301    match expected.index {
3302        Some(current) if index < current => {}
3303        Some(current) if index == current => {
3304            symbols.extend_btree_set(&mut expected.symbols);
3305        }
3306        _ => {
3307            expected.index = Some(index);
3308            expected.symbols = symbols.to_btree_set();
3309        }
3310    }
3311}
3312
3313/// Folds a pruned transition's FIRST set into the farthest-expected accumulator.
3314fn record_pruned_transition_expected(
3315    set: &TransitionLookSet,
3316    index: usize,
3317    expected: &mut ExpectedTokens,
3318) {
3319    match expected.index {
3320        Some(current) if index < current => {}
3321        Some(current) if index == current => {
3322            set.symbols.extend_btree_set(&mut expected.symbols);
3323        }
3324        _ => {
3325            expected.index = Some(index);
3326            expected.symbols = set.symbols.to_btree_set();
3327        }
3328    }
3329}
3330
3331fn rule_first_set_inner(
3332    atn: &Atn,
3333    state_number: usize,
3334    rule_stop_state: usize,
3335    ctx: &mut FirstSetCtx<'_>,
3336    visited: &mut BTreeSet<usize>,
3337    first: &mut FirstSet,
3338) {
3339    if !visited.insert(state_number) {
3340        return;
3341    }
3342    if state_number == rule_stop_state {
3343        first.nullable = true;
3344        return;
3345    }
3346    let Some(state) = atn.state(state_number) else {
3347        return;
3348    };
3349    for transition in &state.transitions() {
3350        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
3351        if !transition_symbols.is_empty() {
3352            first.symbols.extend_iter(transition_symbols);
3353            continue;
3354        }
3355        match &transition.data() {
3356            Transition::Epsilon { target }
3357            | Transition::Action { target, .. }
3358            | Transition::Predicate { target, .. }
3359            | Transition::Precedence { target, .. } => {
3360                rule_first_set_inner(atn, *target, rule_stop_state, ctx, visited, first);
3361            }
3362            Transition::Rule {
3363                target,
3364                rule_index,
3365                follow_state,
3366                ..
3367            } => {
3368                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3369                    continue;
3370                };
3371                let child_key = (*target, child_stop);
3372                if ctx.in_progress.contains(&child_key) && !ctx.cache.contains_key(&child_key) {
3373                    ctx.hit_cycle = true;
3374                }
3375                let child = rule_first_set_cached(atn, *target, child_stop, ctx);
3376                first.symbols.extend_from(&child.symbols);
3377                if child.nullable {
3378                    rule_first_set_inner(atn, *follow_state, rule_stop_state, ctx, visited, first);
3379                }
3380            }
3381            Transition::Atom { .. }
3382            | Transition::Range { .. }
3383            | Transition::Set { .. }
3384            | Transition::NotSet { .. }
3385            | Transition::Wildcard { .. } => {}
3386        }
3387    }
3388}
3389
3390/// Returns token types that can resume parsing from `state_number` after a
3391/// failed child rule, following rule calls as well as epsilon transitions.
3392fn state_sync_symbols(atn: &Atn, state_number: usize, stop_state: usize) -> BTreeSet<i32> {
3393    let mut symbols = BTreeSet::new();
3394    state_sync_symbols_inner(
3395        atn,
3396        state_number,
3397        stop_state,
3398        &mut BTreeSet::new(),
3399        &mut symbols,
3400    );
3401    symbols
3402}
3403
3404/// Walks epsilon-like continuations from a parent follow state until it finds
3405/// consuming tokens that can anchor recovery, or EOF if the parent rule can end.
3406fn state_sync_symbols_inner(
3407    atn: &Atn,
3408    state_number: usize,
3409    stop_state: usize,
3410    visited: &mut BTreeSet<usize>,
3411    symbols: &mut BTreeSet<i32>,
3412) {
3413    if !visited.insert(state_number) {
3414        return;
3415    }
3416    if state_number == stop_state {
3417        symbols.insert(TOKEN_EOF);
3418        return;
3419    }
3420    let Some(state) = atn.state(state_number) else {
3421        return;
3422    };
3423    for transition in &state.transitions() {
3424        let transition_symbols = transition_expected_symbols(transition, atn.max_token_type());
3425        if transition_symbols.is_empty() {
3426            match &transition.data() {
3427                Transition::Rule { target, .. }
3428                | Transition::Epsilon { target }
3429                | Transition::Action { target, .. }
3430                | Transition::Predicate { target, .. }
3431                | Transition::Precedence { target, .. } => {
3432                    state_sync_symbols_inner(atn, *target, stop_state, visited, symbols);
3433                }
3434                Transition::Atom { .. }
3435                | Transition::Range { .. }
3436                | Transition::Set { .. }
3437                | Transition::NotSet { .. }
3438                | Transition::Wildcard { .. } => {}
3439            }
3440        } else {
3441            symbols.extend(transition_symbols);
3442        }
3443    }
3444}
3445
3446#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
3447struct OperatorSymbolReachability {
3448    /// One token completes an unconditional operator token-prefix.
3449    single_token: bool,
3450    /// An unconditional operator path requires more tokens before its operand.
3451    multi_token: bool,
3452    /// At least one matching operator path depends on a semantic predicate.
3453    predicate_dependent: bool,
3454}
3455
3456impl OperatorSymbolReachability {
3457    const ADAPTIVE_FALLBACK: Self = Self {
3458        single_token: false,
3459        multi_token: false,
3460        predicate_dependent: true,
3461    };
3462
3463    const fn single_token(predicate_dependent: bool) -> Self {
3464        if predicate_dependent {
3465            Self {
3466                single_token: false,
3467                multi_token: false,
3468                predicate_dependent: true,
3469            }
3470        } else {
3471            Self {
3472                single_token: true,
3473                multi_token: false,
3474                predicate_dependent: false,
3475            }
3476        }
3477    }
3478
3479    const fn multi_token(predicate_dependent: bool) -> Self {
3480        if predicate_dependent {
3481            Self {
3482                single_token: false,
3483                multi_token: false,
3484                predicate_dependent: true,
3485            }
3486        } else {
3487            Self {
3488                single_token: false,
3489                multi_token: true,
3490                predicate_dependent: false,
3491            }
3492        }
3493    }
3494
3495    const fn union(self, other: Self) -> Self {
3496        Self {
3497            single_token: self.single_token || other.single_token,
3498            multi_token: self.multi_token || other.multi_token,
3499            predicate_dependent: self.predicate_dependent || other.predicate_dependent,
3500        }
3501    }
3502}
3503
3504#[derive(Clone, Copy)]
3505struct OperatorReachabilityRequest {
3506    symbol: i32,
3507    precedence: i32,
3508    predicate_dependent: bool,
3509    operator_rule_index: usize,
3510}
3511
3512#[derive(Clone, Copy, Debug)]
3513struct OperatorRuleContinuation {
3514    stop_state: usize,
3515    follow_state: usize,
3516    return_precedence: i32,
3517}
3518
3519struct NullablePrecedenceCtx {
3520    cache: FxHashMap<(usize, usize, i32, bool), bool>,
3521    in_progress: BTreeSet<(usize, usize, i32, bool)>,
3522    hit_cycle: bool,
3523}
3524
3525fn state_is_nullable_with_precedence(
3526    atn: &Atn,
3527    state_number: usize,
3528    stop_state_number: usize,
3529    precedence: i32,
3530    allow_predicates: bool,
3531    ctx: &mut NullablePrecedenceCtx,
3532) -> bool {
3533    let saved_hit_cycle = ctx.hit_cycle;
3534    ctx.hit_cycle = false;
3535    let nullable = state_is_nullable_with_precedence_cached(
3536        atn,
3537        state_number,
3538        stop_state_number,
3539        precedence,
3540        allow_predicates,
3541        ctx,
3542    );
3543    ctx.hit_cycle = saved_hit_cycle;
3544    nullable
3545}
3546
3547fn state_is_nullable_with_precedence_cached(
3548    atn: &Atn,
3549    state_number: usize,
3550    stop_state_number: usize,
3551    precedence: i32,
3552    allow_predicates: bool,
3553    ctx: &mut NullablePrecedenceCtx,
3554) -> bool {
3555    if state_number == stop_state_number {
3556        return true;
3557    }
3558    let key = (
3559        state_number,
3560        stop_state_number,
3561        precedence,
3562        allow_predicates,
3563    );
3564    if let Some(cached) = ctx.cache.get(&key) {
3565        return *cached;
3566    }
3567    if !ctx.in_progress.insert(key) {
3568        ctx.hit_cycle = true;
3569        return false;
3570    }
3571    let saved_hit_cycle = ctx.hit_cycle;
3572    ctx.hit_cycle = false;
3573    let nullable = atn.state(state_number).is_some_and(|state| {
3574        state
3575            .transitions()
3576            .iter()
3577            .any(|transition| match &transition.data() {
3578                Transition::Rule {
3579                    target,
3580                    rule_index,
3581                    follow_state,
3582                    precedence: rule_precedence,
3583                } => {
3584                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3585                        return false;
3586                    };
3587                    state_is_nullable_with_precedence_cached(
3588                        atn,
3589                        *target,
3590                        child_stop,
3591                        *rule_precedence,
3592                        allow_predicates,
3593                        ctx,
3594                    ) && state_is_nullable_with_precedence_cached(
3595                        atn,
3596                        *follow_state,
3597                        stop_state_number,
3598                        precedence,
3599                        allow_predicates,
3600                        ctx,
3601                    )
3602                }
3603                Transition::Epsilon { target } | Transition::Action { target, .. } => {
3604                    state_is_nullable_with_precedence_cached(
3605                        atn,
3606                        *target,
3607                        stop_state_number,
3608                        precedence,
3609                        allow_predicates,
3610                        ctx,
3611                    )
3612                }
3613                Transition::Predicate { target, .. } if allow_predicates => {
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::Precedence {
3624                    target,
3625                    precedence: transition_precedence,
3626                } if *transition_precedence >= precedence => {
3627                    state_is_nullable_with_precedence_cached(
3628                        atn,
3629                        *target,
3630                        stop_state_number,
3631                        precedence,
3632                        allow_predicates,
3633                        ctx,
3634                    )
3635                }
3636                Transition::Atom { .. }
3637                | Transition::Range { .. }
3638                | Transition::Set { .. }
3639                | Transition::NotSet { .. }
3640                | Transition::Wildcard { .. }
3641                | Transition::Predicate { .. }
3642                | Transition::Precedence { .. } => false,
3643            })
3644    });
3645    ctx.in_progress.remove(&key);
3646    if !ctx.hit_cycle {
3647        ctx.cache.insert(key, nullable);
3648    }
3649    ctx.hit_cycle = saved_hit_cycle || ctx.hit_cycle;
3650    nullable
3651}
3652
3653/// Classifies what remains after the operator's first token is matched.
3654fn state_operator_token_prefix_reachability(
3655    atn: &Atn,
3656    state_number: usize,
3657    request: OperatorReachabilityRequest,
3658    continuations: &[OperatorRuleContinuation],
3659    visited: &mut BTreeSet<(usize, i32, bool)>,
3660) -> OperatorSymbolReachability {
3661    let key = (
3662        state_number,
3663        request.precedence,
3664        request.predicate_dependent,
3665    );
3666    if !visited.insert(key) {
3667        // Recursive helper rules can grow the return stack without consuming
3668        // input. Delegate cycles to adaptive prediction instead of forcing a
3669        // potentially incomplete one-token answer.
3670        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3671    }
3672    if let Some((continuation, remaining)) = continuations.split_last()
3673        && state_number == continuation.stop_state
3674    {
3675        let result = state_operator_token_prefix_reachability(
3676            atn,
3677            continuation.follow_state,
3678            OperatorReachabilityRequest {
3679                precedence: continuation.return_precedence,
3680                ..request
3681            },
3682            remaining,
3683            visited,
3684        );
3685        visited.remove(&key);
3686        return result;
3687    }
3688    let Some(state) = atn.state(state_number) else {
3689        visited.remove(&key);
3690        return OperatorSymbolReachability::default();
3691    };
3692    let completes_operator = match state.kind() {
3693        AtnStateKind::RuleStop => continuations.is_empty(),
3694        AtnStateKind::StarLoopBack
3695        | AtnStateKind::StarLoopEntry
3696        | AtnStateKind::PlusLoopBack
3697        | AtnStateKind::LoopEnd => state.rule_index() == Some(request.operator_rule_index),
3698        _ => false,
3699    };
3700    if completes_operator {
3701        visited.remove(&key);
3702        return OperatorSymbolReachability::single_token(request.predicate_dependent);
3703    }
3704    let mut reachability = OperatorSymbolReachability::default();
3705    for transition in &state.transitions() {
3706        let transition_reachability = match &transition.data() {
3707            Transition::Rule { rule_index, .. } if *rule_index == request.operator_rule_index => {
3708                OperatorSymbolReachability::single_token(request.predicate_dependent)
3709            }
3710            Transition::Rule {
3711                target,
3712                rule_index,
3713                follow_state,
3714                precedence: rule_precedence,
3715            } => {
3716                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3717                    continue;
3718                };
3719                let mut nested = continuations.to_vec();
3720                nested.push(OperatorRuleContinuation {
3721                    stop_state: child_stop,
3722                    follow_state: *follow_state,
3723                    return_precedence: request.precedence,
3724                });
3725                state_operator_token_prefix_reachability(
3726                    atn,
3727                    *target,
3728                    OperatorReachabilityRequest {
3729                        precedence: *rule_precedence,
3730                        ..request
3731                    },
3732                    &nested,
3733                    visited,
3734                )
3735            }
3736            Transition::Epsilon { target } | Transition::Action { target, .. } => {
3737                state_operator_token_prefix_reachability(
3738                    atn,
3739                    *target,
3740                    request,
3741                    continuations,
3742                    visited,
3743                )
3744            }
3745            Transition::Precedence {
3746                target,
3747                precedence: transition_precedence,
3748            } => {
3749                if *transition_precedence < request.precedence {
3750                    OperatorSymbolReachability::default()
3751                } else {
3752                    state_operator_token_prefix_reachability(
3753                        atn,
3754                        *target,
3755                        request,
3756                        continuations,
3757                        visited,
3758                    )
3759                }
3760            }
3761            Transition::Predicate { target, .. } => state_operator_token_prefix_reachability(
3762                atn,
3763                *target,
3764                OperatorReachabilityRequest {
3765                    predicate_dependent: true,
3766                    ..request
3767                },
3768                continuations,
3769                visited,
3770            ),
3771            Transition::Atom { .. }
3772            | Transition::Range { .. }
3773            | Transition::Set { .. }
3774            | Transition::NotSet { .. }
3775            | Transition::Wildcard { .. } => {
3776                OperatorSymbolReachability::multi_token(request.predicate_dependent)
3777            }
3778        };
3779        reachability = reachability.union(transition_reachability);
3780    }
3781    visited.remove(&key);
3782    reachability
3783}
3784
3785fn state_can_reach_symbol_with_precedence(
3786    atn: &Atn,
3787    state_number: usize,
3788    request: OperatorReachabilityRequest,
3789    nullable_ctx: &mut NullablePrecedenceCtx,
3790    continuations: &mut Vec<OperatorRuleContinuation>,
3791    visited: &mut BTreeSet<(usize, i32, bool)>,
3792) -> OperatorSymbolReachability {
3793    let key = (
3794        state_number,
3795        request.precedence,
3796        request.predicate_dependent,
3797    );
3798    if !visited.insert(key) {
3799        return OperatorSymbolReachability::ADAPTIVE_FALLBACK;
3800    }
3801    let Some(state) = atn.state(state_number) else {
3802        visited.remove(&key);
3803        return OperatorSymbolReachability::default();
3804    };
3805    let mut reachability = OperatorSymbolReachability::default();
3806    for transition in &state.transitions() {
3807        if transition.matches(request.symbol, 1, atn.max_token_type()) {
3808            reachability = reachability.union(state_operator_token_prefix_reachability(
3809                atn,
3810                transition.target(),
3811                request,
3812                continuations,
3813                &mut BTreeSet::new(),
3814            ));
3815            continue;
3816        }
3817        let transition_reachability = match &transition.data() {
3818            Transition::Rule {
3819                target,
3820                rule_index,
3821                follow_state,
3822                precedence: rule_precedence,
3823            } => {
3824                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
3825                    continue;
3826                };
3827                continuations.push(OperatorRuleContinuation {
3828                    stop_state: child_stop,
3829                    follow_state: *follow_state,
3830                    return_precedence: request.precedence,
3831                });
3832                let mut result = state_can_reach_symbol_with_precedence(
3833                    atn,
3834                    *target,
3835                    OperatorReachabilityRequest {
3836                        precedence: *rule_precedence,
3837                        ..request
3838                    },
3839                    nullable_ctx,
3840                    continuations,
3841                    visited,
3842                );
3843                continuations.pop();
3844                if state_is_nullable_with_precedence(
3845                    atn,
3846                    *target,
3847                    child_stop,
3848                    *rule_precedence,
3849                    true,
3850                    nullable_ctx,
3851                ) {
3852                    let child_predicate_dependent = request.predicate_dependent
3853                        || !state_is_nullable_with_precedence(
3854                            atn,
3855                            *target,
3856                            child_stop,
3857                            *rule_precedence,
3858                            false,
3859                            nullable_ctx,
3860                        );
3861                    result = result.union(state_can_reach_symbol_with_precedence(
3862                        atn,
3863                        *follow_state,
3864                        OperatorReachabilityRequest {
3865                            predicate_dependent: child_predicate_dependent,
3866                            ..request
3867                        },
3868                        nullable_ctx,
3869                        continuations,
3870                        visited,
3871                    ));
3872                }
3873                result
3874            }
3875            Transition::Epsilon { target }
3876            | Transition::Action { target, .. }
3877            | Transition::Precedence { target, .. } => {
3878                if matches!(
3879                    &transition.data(),
3880                    Transition::Precedence {
3881                        precedence: transition_precedence,
3882                        ..
3883                    } if *transition_precedence < request.precedence
3884                ) {
3885                    continue;
3886                }
3887                state_can_reach_symbol_with_precedence(
3888                    atn,
3889                    *target,
3890                    request,
3891                    nullable_ctx,
3892                    continuations,
3893                    visited,
3894                )
3895            }
3896            Transition::Predicate { target, .. } => state_can_reach_symbol_with_precedence(
3897                atn,
3898                *target,
3899                OperatorReachabilityRequest {
3900                    predicate_dependent: true,
3901                    ..request
3902                },
3903                nullable_ctx,
3904                continuations,
3905                visited,
3906            ),
3907            Transition::Atom { .. }
3908            | Transition::Range { .. }
3909            | Transition::Set { .. }
3910            | Transition::NotSet { .. }
3911            | Transition::Wildcard { .. } => OperatorSymbolReachability::default(),
3912        };
3913        reachability = reachability.union(transition_reachability);
3914    }
3915    visited.remove(&key);
3916    reachability
3917}
3918
3919fn left_recursive_operator_lookahead(
3920    atn: &Atn,
3921    state_number: usize,
3922    precedence: i32,
3923) -> LeftRecursiveOperatorLookahead {
3924    let Some(state) = atn.state(state_number) else {
3925        return LeftRecursiveOperatorLookahead::default();
3926    };
3927    let Some(operator_rule_index) = state.rule_index() else {
3928        return LeftRecursiveOperatorLookahead::default();
3929    };
3930    let mut lookahead = LeftRecursiveOperatorLookahead::default();
3931    let mut nullable_ctx = NullablePrecedenceCtx {
3932        cache: FxHashMap::default(),
3933        in_progress: BTreeSet::new(),
3934        hit_cycle: false,
3935    };
3936    for transition in &state.transitions() {
3937        let target = transition.target();
3938        if atn
3939            .state(target)
3940            .is_some_and(|state| state.kind() == AtnStateKind::LoopEnd)
3941        {
3942            continue;
3943        }
3944        for symbol in 1..=atn.max_token_type() {
3945            let reachability = state_can_reach_symbol_with_precedence(
3946                atn,
3947                target,
3948                OperatorReachabilityRequest {
3949                    symbol,
3950                    precedence,
3951                    predicate_dependent: false,
3952                    operator_rule_index,
3953                },
3954                &mut nullable_ctx,
3955                &mut Vec::new(),
3956                &mut BTreeSet::new(),
3957            );
3958            if reachability.single_token {
3959                lookahead.single_token.insert(symbol);
3960            }
3961            if reachability.multi_token {
3962                lookahead.multi_token_prefix.insert(symbol);
3963            }
3964            if reachability.predicate_dependent {
3965                lookahead.predicate_dependent.insert(symbol);
3966            }
3967        }
3968    }
3969    lookahead
3970}
3971
3972#[derive(Debug, Default)]
3973struct StateBeforeStopLookahead {
3974    symbols: TokenBitSet,
3975    reaches_context_boundary: bool,
3976}
3977
3978fn state_before_stop_lookahead(
3979    atn: &Atn,
3980    state_number: usize,
3981    stop_state_number: usize,
3982) -> Rc<StateBeforeStopLookahead> {
3983    with_shared_atn_caches(atn, |cache| {
3984        let key = (state_number, stop_state_number);
3985        if let Some(cached) = cache.state_before_stop_lookahead.get(&key) {
3986            return Rc::clone(cached);
3987        }
3988        let mut lookahead = StateBeforeStopLookahead::default();
3989        state_before_stop_lookahead_inner(
3990            atn,
3991            state_number,
3992            stop_state_number,
3993            &mut BTreeSet::new(),
3994            &mut cache.first_set,
3995            &mut lookahead,
3996        );
3997        let lookahead = Rc::new(lookahead);
3998        cache
3999            .state_before_stop_lookahead
4000            .insert(key, Rc::clone(&lookahead));
4001        lookahead
4002    })
4003}
4004
4005fn state_before_stop_lookahead_inner(
4006    atn: &Atn,
4007    state_number: usize,
4008    stop_state_number: usize,
4009    visited: &mut BTreeSet<usize>,
4010    first_set_cache: &mut FirstSetCache,
4011    lookahead: &mut StateBeforeStopLookahead,
4012) {
4013    if state_number == stop_state_number {
4014        lookahead.reaches_context_boundary = true;
4015        return;
4016    }
4017    if !visited.insert(state_number) {
4018        return;
4019    }
4020    let Some(state) = atn.state(state_number) else {
4021        return;
4022    };
4023    if state.kind() == AtnStateKind::RuleStop {
4024        lookahead.reaches_context_boundary = true;
4025        return;
4026    }
4027    for transition in &state.transitions() {
4028        match &transition.data() {
4029            Transition::Epsilon { target }
4030            | Transition::Action { target, .. }
4031            | Transition::Predicate { target, .. }
4032            | Transition::Precedence { target, .. } => {
4033                state_before_stop_lookahead_inner(
4034                    atn,
4035                    *target,
4036                    stop_state_number,
4037                    visited,
4038                    first_set_cache,
4039                    lookahead,
4040                );
4041            }
4042            Transition::Rule {
4043                target,
4044                rule_index,
4045                follow_state,
4046                ..
4047            } => {
4048                let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
4049                    continue;
4050                };
4051                let child = rule_first_set(atn, *target, child_stop, first_set_cache);
4052                lookahead.symbols.extend_from(&child.symbols);
4053                if child.nullable {
4054                    state_before_stop_lookahead_inner(
4055                        atn,
4056                        *follow_state,
4057                        stop_state_number,
4058                        visited,
4059                        first_set_cache,
4060                        lookahead,
4061                    );
4062                }
4063            }
4064            Transition::Atom { .. }
4065            | Transition::Range { .. }
4066            | Transition::Set { .. }
4067            | Transition::NotSet { .. }
4068            | Transition::Wildcard { .. } => {
4069                lookahead.symbols.extend_iter(transition_expected_symbols(
4070                    transition,
4071                    atn.max_token_type(),
4072                ));
4073            }
4074        }
4075    }
4076}
4077
4078fn caller_context_can_match_symbol_before_state(
4079    atn: &Atn,
4080    return_states: impl DoubleEndedIterator<Item = usize>,
4081    stop_state_number: usize,
4082    symbol: i32,
4083) -> bool {
4084    for return_state in return_states.rev() {
4085        let lookahead = state_before_stop_lookahead(atn, return_state, stop_state_number);
4086        if lookahead.symbols.contains(symbol) {
4087            return true;
4088        }
4089        if !lookahead.reaches_context_boundary {
4090            return false;
4091        }
4092    }
4093    false
4094}
4095
4096/// Carries recovery expectations and their restart state through epsilon-only
4097/// paths. ANTLR can report and repair at the decision state even when the
4098/// failed consuming transition is nested under block or loop epsilon edges.
4099fn next_recovery_context(
4100    atn: &Atn,
4101    state: AtnState<'_>,
4102    inherited: &BTreeSet<i32>,
4103    inherited_state: Option<usize>,
4104) -> (BTreeSet<i32>, Option<usize>) {
4105    let state_symbols = state_expected_symbols(atn, state.state_number());
4106    if state.transitions().len() > 1 && !state_symbols.is_empty() {
4107        let mut symbols = state_symbols;
4108        symbols.extend(inherited.iter().copied());
4109        return (symbols, Some(state.state_number()));
4110    }
4111    (inherited.clone(), inherited_state)
4112}
4113
4114fn recovery_expected_symbols(
4115    atn: &Atn,
4116    state_number: usize,
4117    inherited: &BTreeSet<i32>,
4118) -> BTreeSet<i32> {
4119    let mut symbols = state_expected_symbols(atn, state_number);
4120    symbols.extend(inherited.iter().copied());
4121    symbols
4122}
4123
4124/// Fast-recognizer variant of [`next_recovery_context`] that reuses the
4125/// parser's cached state-expected-symbols sets and the inherited `Rc`
4126/// without copying when the state cannot widen recovery.
4127fn fast_next_recovery_context<S, H>(
4128    parser: &mut BaseParser<S, H>,
4129    atn: &Atn,
4130    state: AtnState<'_>,
4131    inherited: &Rc<BTreeSet<i32>>,
4132    inherited_state: Option<usize>,
4133) -> (Rc<BTreeSet<i32>>, Option<usize>)
4134where
4135    S: TokenSource,
4136    H: SemanticHooks,
4137{
4138    if state.transitions().len() <= 1 {
4139        return (Rc::clone(inherited), inherited_state);
4140    }
4141    let state_symbols = parser.cached_state_expected_symbols(atn, state.state_number());
4142    if state_symbols.is_empty() {
4143        return (Rc::clone(inherited), inherited_state);
4144    }
4145    if inherited.is_empty() {
4146        return (state_symbols, Some(state.state_number()));
4147    }
4148    if Rc::ptr_eq(&state_symbols, inherited) {
4149        return (state_symbols, Some(state.state_number()));
4150    }
4151    let mut combined = (*state_symbols).clone();
4152    combined.extend(inherited.iter().copied());
4153    (
4154        parser.intern_recovery_symbols(combined),
4155        Some(state.state_number()),
4156    )
4157}
4158
4159/// Fast-recognizer variant of [`recovery_expected_symbols`] that reuses the
4160/// cached state-expected-symbols and avoids cloning when no widening is
4161/// needed.
4162fn fast_recovery_expected_symbols<S, H>(
4163    parser: &mut BaseParser<S, H>,
4164    atn: &Atn,
4165    state_number: usize,
4166    inherited: &Rc<BTreeSet<i32>>,
4167) -> Rc<BTreeSet<i32>>
4168where
4169    S: TokenSource,
4170    H: SemanticHooks,
4171{
4172    let cached = parser.cached_state_expected_symbols(atn, state_number);
4173    if inherited.is_empty() {
4174        return cached;
4175    }
4176    if cached.is_empty() {
4177        return Rc::clone(inherited);
4178    }
4179    if Rc::ptr_eq(&cached, inherited) {
4180        return cached;
4181    }
4182    let mut combined = (*cached).clone();
4183    combined.extend(inherited.iter().copied());
4184    parser.intern_recovery_symbols(combined)
4185}
4186
4187struct ParserTableSemCtx<'a> {
4188    member_values: &'a mut MemberEnv,
4189    return_values: &'a mut BTreeMap<String, i64>,
4190}
4191
4192impl semir::PredContext for ParserTableSemCtx<'_> {
4193    type TokenText<'a>
4194        = &'a str
4195    where
4196        Self: 'a;
4197
4198    fn la(&mut self, _offset: isize) -> i64 {
4199        i64::from(TOKEN_EOF)
4200    }
4201
4202    fn token_text(&mut self, _offset: isize) -> Option<Self::TokenText<'_>> {
4203        None
4204    }
4205
4206    fn token_index_adjacent(&mut self) -> bool {
4207        false
4208    }
4209
4210    fn ctx_rule_text(&self, _rule_index: usize) -> Option<String> {
4211        None
4212    }
4213
4214    fn member(&self, member: usize) -> Option<i64> {
4215        Some(self.member_values.scalar(member).unwrap_or_default())
4216    }
4217
4218    fn member_top(&self, member: usize) -> Option<i64> {
4219        self.member_values.stack_top(member)
4220    }
4221
4222    fn member_len(&self, member: usize) -> usize {
4223        self.member_values.stack_len(member)
4224    }
4225
4226    fn local_arg(&self) -> Option<i64> {
4227        None
4228    }
4229
4230    fn column(&self) -> Option<i64> {
4231        None
4232    }
4233
4234    fn token_start_column(&self) -> Option<i64> {
4235        None
4236    }
4237
4238    fn token_text_so_far(&self) -> Option<String> {
4239        None
4240    }
4241
4242    fn hook(&mut self, _hook: HookId) -> bool {
4243        false
4244    }
4245}
4246
4247impl semir::ActContext for ParserTableSemCtx<'_> {
4248    fn set_member(&mut self, member: usize, value: i64) {
4249        self.member_values.set_scalar(member, value);
4250    }
4251
4252    fn push_member(&mut self, member: usize, value: i64) {
4253        self.member_values.push_stack(member, value);
4254    }
4255
4256    fn pop_member(&mut self, member: usize) -> Option<i64> {
4257        self.member_values.pop_stack(member)
4258    }
4259
4260    fn set_return(&mut self, name: &str, value: i64) {
4261        self.return_values.insert(name.to_owned(), value);
4262    }
4263
4264    fn action_hook(&mut self, _hook: HookId) {}
4265}
4266
4267/// Applies generated integer-member side effects to one speculative path.
4268fn apply_member_actions(
4269    source_state: usize,
4270    actions: &[ParserMemberAction],
4271    semantics: Option<&ParserSemantics>,
4272    values: &mut MemberEnv,
4273) {
4274    for action in actions
4275        .iter()
4276        .filter(|action| action.source_state == source_state)
4277    {
4278        values.add_scalar(action.member, action.delta);
4279    }
4280    let Some(semantics) = semantics else {
4281        return;
4282    };
4283    let mut return_values = BTreeMap::new();
4284    let mut ctx = ParserTableSemCtx {
4285        member_values: values,
4286        return_values: &mut return_values,
4287    };
4288    for action in semantics
4289        .actions
4290        .iter()
4291        .filter(|action| action.source_state == source_state && action.speculative)
4292    {
4293        semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
4294    }
4295}
4296
4297/// Returns the speculative member state after replaying one ATN action state.
4298fn member_values_after_action(
4299    source_state: usize,
4300    actions: &[ParserMemberAction],
4301    semantics: Option<&ParserSemantics>,
4302    values: &MemberEnv,
4303) -> MemberEnv {
4304    let mut values = values.clone();
4305    apply_member_actions(source_state, actions, semantics, &mut values);
4306    values
4307}
4308
4309/// Returns the speculative rule-return state after replaying one ATN action.
4310fn return_values_after_action(
4311    source_state: usize,
4312    rule_index: usize,
4313    actions: &[ParserReturnAction],
4314    semantics: Option<&ParserSemantics>,
4315    values: &BTreeMap<String, i64>,
4316) -> BTreeMap<String, i64> {
4317    let mut values = values.clone();
4318    for action in actions
4319        .iter()
4320        .filter(|action| action.source_state == source_state && action.rule_index == rule_index)
4321    {
4322        values.insert(action.name.to_owned(), action.value);
4323    }
4324    if let Some(semantics) = semantics {
4325        let mut member_values = MemberEnv::new();
4326        let mut ctx = ParserTableSemCtx {
4327            member_values: &mut member_values,
4328            return_values: &mut values,
4329        };
4330        for action in semantics.actions.iter().filter(|action| {
4331            action.source_state == source_state
4332                && action.rule_index == rule_index
4333                && !action.speculative
4334        }) {
4335            semir::exec_stmt(&semantics.ir, action.stmt, &mut ctx);
4336        }
4337    }
4338    values
4339}
4340
4341/// Resolves the integer argument visible to a child rule invocation.
4342fn rule_local_int_arg(
4343    rule_args: &[ParserRuleArg],
4344    source_state: usize,
4345    rule_index: usize,
4346    local_int_arg: Option<(usize, i64)>,
4347) -> Option<(usize, i64)> {
4348    rule_args
4349        .iter()
4350        .find(|arg| arg.source_state == source_state && arg.rule_index == rule_index)
4351        .map(|arg| {
4352            let value = if arg.inherit_local {
4353                local_int_arg.map_or(arg.value, |(_, value)| value)
4354            } else {
4355                arg.value
4356            };
4357            (rule_index, value)
4358        })
4359}
4360
4361/// Builds the terminal recognition outcome for a path that reached its stop
4362/// state.
4363fn stop_outcome(
4364    index: usize,
4365    consumed_eof: bool,
4366    rule_alt_number: usize,
4367    member_values: MemberEnv,
4368    return_values: BTreeMap<String, i64>,
4369) -> Vec<RecognizeOutcome> {
4370    vec![RecognizeOutcome {
4371        index,
4372        consumed_eof,
4373        alt_number: rule_alt_number,
4374        member_values,
4375        return_values,
4376        diagnostics: DiagnosticSeqId::EMPTY,
4377        decisions: Vec::new(),
4378        actions: Vec::new(),
4379        nodes: NodeSeqId::EMPTY,
4380    }]
4381}
4382
4383fn atn_has_observable_action_transitions(atn: &Atn) -> bool {
4384    with_shared_atn_caches(atn, |cache| {
4385        *cache.observable_action_transitions.get_or_insert_with(|| {
4386            atn.states().any(|state| {
4387                state.transitions().iter().any(|transition| {
4388                    matches!(
4389                        &transition.data(),
4390                        Transition::Action {
4391                            action_index: Some(_),
4392                            ..
4393                        }
4394                    )
4395                })
4396            })
4397        })
4398    })
4399}
4400
4401fn atn_has_predicate_transitions(atn: &Atn) -> bool {
4402    with_shared_atn_caches(atn, |cache| {
4403        *cache.predicate_transitions.get_or_insert_with(|| {
4404            atn.states().any(|state| {
4405                state
4406                    .transitions()
4407                    .iter()
4408                    .any(|transition| matches!(&transition.data(), Transition::Predicate { .. }))
4409            })
4410        })
4411    })
4412}
4413
4414/// Reports whether predicates are the only observable semantics the fast
4415/// recognizer must preserve. Without path-local actions, arguments, or return
4416/// state, repeated evaluation at one coordinate and input index receives the
4417/// same runtime context.
4418fn can_use_fast_predicate_recognizer(atn: &Atn, options: &ParserRuntimeOptions<'_>) -> bool {
4419    options.init_action_rules.is_empty()
4420        && options.action_indices.is_empty()
4421        && !options.track_alt_numbers
4422        && options
4423            .predicates
4424            .iter()
4425            .all(|(_, _, predicate)| predicate.failure_message().is_none())
4426        && options.semantics.is_none_or(|semantics| {
4427            semantics.actions.is_empty()
4428                && semantics
4429                    .predicates
4430                    .iter()
4431                    .all(|predicate| predicate.failure_message.is_none())
4432        })
4433        && options.rule_args.is_empty()
4434        && options.member_actions.is_empty()
4435        && options.return_actions.is_empty()
4436        && !atn_has_observable_action_transitions(atn)
4437}
4438
4439#[derive(Clone, Debug, Eq, PartialEq)]
4440struct RecognizeRequest<'a> {
4441    state_number: usize,
4442    stop_state: usize,
4443    index: usize,
4444    rule_start_index: usize,
4445    decision_start_index: Option<usize>,
4446    init_action_rules: &'a BTreeSet<usize>,
4447    predicates: &'a [(usize, usize, ParserPredicate)],
4448    semantics: Option<&'a ParserSemantics>,
4449    rule_args: &'a [ParserRuleArg],
4450    member_actions: &'a [ParserMemberAction],
4451    return_actions: &'a [ParserReturnAction],
4452    local_int_arg: Option<(usize, i64)>,
4453    member_values: MemberEnv,
4454    return_values: BTreeMap<String, i64>,
4455    rule_alt_number: usize,
4456    track_alt_numbers: bool,
4457    consumed_eof: bool,
4458    committed_decision: bool,
4459    /// Current left-recursive precedence threshold, matching ANTLR's
4460    /// `precpred(_ctx, k)` check for generated precedence rules.
4461    precedence: i32,
4462    depth: usize,
4463    recovery_symbols: BTreeSet<i32>,
4464    recovery_state: Option<usize>,
4465}
4466
4467#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
4468struct RecognizeKey {
4469    state_number: usize,
4470    stop_state: usize,
4471    index: usize,
4472    rule_start_index: usize,
4473    decision_start_index: Option<usize>,
4474    local_int_arg: Option<(usize, i64)>,
4475    member_values: MemberEnv,
4476    return_values: BTreeMap<String, i64>,
4477    rule_alt_number: usize,
4478    track_alt_numbers: bool,
4479    consumed_eof: bool,
4480    committed_decision: bool,
4481    precedence: i32,
4482    recovery_symbols: BTreeSet<i32>,
4483    recovery_state: Option<usize>,
4484}
4485
4486#[derive(Clone, Debug, Eq, PartialEq)]
4487struct EpsilonActionStep {
4488    source_state: usize,
4489    target: usize,
4490    action_rule_index: Option<usize>,
4491    action_index: Option<usize>,
4492    left_recursive_boundary: Option<usize>,
4493    decision: Option<usize>,
4494    decision_start_index: Option<usize>,
4495    alt_number: usize,
4496    recovery_symbols: BTreeSet<i32>,
4497    recovery_state: Option<usize>,
4498}
4499
4500struct RecognizeScratch<'a> {
4501    visiting: &'a mut BTreeSet<RecognizeKey>,
4502    memo: &'a mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4503    expected: &'a mut ExpectedTokens,
4504}
4505
4506#[derive(Clone, Debug, Eq, PartialEq)]
4507struct FastRecognizeRequest {
4508    state_number: usize,
4509    stop_state: usize,
4510    index: usize,
4511    rule_start_index: usize,
4512    decision_start_index: Option<usize>,
4513    precedence: i32,
4514    depth: usize,
4515    recovery_symbols: Rc<BTreeSet<i32>>,
4516    recovery_state: Option<usize>,
4517}
4518
4519#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4520struct FastRecognizeTopRequest {
4521    start_state: usize,
4522    stop_state: usize,
4523    start_index: usize,
4524    precedence: i32,
4525    caller_follow_state: Option<usize>,
4526}
4527
4528#[derive(Clone, Copy, Debug)]
4529struct FastPredicateContext<'a> {
4530    predicates: &'a [(usize, usize, ParserPredicate)],
4531    semantics: Option<&'a ParserSemantics>,
4532    member_values: &'a MemberEnv,
4533}
4534
4535#[derive(Clone, Copy, Debug, Default)]
4536struct AltNumberTracking {
4537    public: bool,
4538    context: bool,
4539}
4540
4541impl AltNumberTracking {
4542    const fn any(self) -> bool {
4543        self.public || self.context
4544    }
4545}
4546
4547struct FastRecognizeScratch<'a, 'b> {
4548    predicate_context: Option<FastPredicateContext<'a>>,
4549    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4550    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4551    expected: &'b mut ExpectedTokens,
4552    native_depth: usize,
4553}
4554
4555#[derive(Clone, Copy, Debug)]
4556struct FastRepetitionShape {
4557    enter_target: usize,
4558    exit_target: usize,
4559    body_stop_state: usize,
4560    enter_transition_index: usize,
4561    exit_transition_index: usize,
4562}
4563
4564#[derive(Clone, Copy, Debug)]
4565struct FastRepetitionPath {
4566    index: usize,
4567    deferred_nodes: FastDeferredNodeId,
4568    diagnostics: DiagnosticSeqId,
4569    consumed_eof: bool,
4570}
4571
4572enum FastRepetitionWork {
4573    Enter(FastRepetitionPath),
4574    Exit(FastRepetitionPath),
4575}
4576
4577/// Dense entered/exited coordinate sets for one repetition walk.
4578///
4579/// The start coordinate stays inline so short loops avoid a heap allocation;
4580/// later token indexes use one byte each instead of two hash-table entries.
4581struct FastRepetitionCoordinates {
4582    base_index: usize,
4583    base_state: u8,
4584    later_states: Vec<u8>,
4585}
4586
4587impl FastRepetitionCoordinates {
4588    const ENTERED: u8 = 0;
4589    const EXITED: u8 = 2;
4590
4591    const fn new(base_index: usize) -> Self {
4592        Self {
4593            base_index,
4594            base_state: 0,
4595            later_states: Vec::new(),
4596        }
4597    }
4598
4599    fn insert_entered(&mut self, path: FastRepetitionPath) -> bool {
4600        self.insert(path.index, path.consumed_eof, Self::ENTERED)
4601    }
4602
4603    fn insert_exited(&mut self, path: FastRepetitionPath) -> bool {
4604        self.insert(path.index, path.consumed_eof, Self::EXITED)
4605    }
4606
4607    fn insert(&mut self, index: usize, consumed_eof: bool, base_bit: u8) -> bool {
4608        let Some(offset) = index.checked_sub(self.base_index) else {
4609            return false;
4610        };
4611        let state = if offset == 0 {
4612            &mut self.base_state
4613        } else {
4614            if self.later_states.len() < offset {
4615                self.later_states.resize(offset, 0);
4616            }
4617            &mut self.later_states[offset - 1]
4618        };
4619        let bit = 1 << (base_bit + u8::from(consumed_eof));
4620        let is_new = *state & bit == 0;
4621        *state |= bit;
4622        is_new
4623    }
4624}
4625
4626fn fast_repetition_shape(atn: &Atn, state: AtnState<'_>) -> Option<FastRepetitionShape> {
4627    if state.precedence_rule_decision()
4628        || !matches!(
4629            state.kind(),
4630            AtnStateKind::StarLoopEntry | AtnStateKind::PlusLoopBack
4631        )
4632        || state.transitions().len() != 2
4633    {
4634        return None;
4635    }
4636    let mut enter = None;
4637    let mut exit = None;
4638    for (index, transition) in state.transitions().iter().enumerate() {
4639        if transition.kind() != ParserTransitionKind::Epsilon {
4640            return None;
4641        }
4642        let target = transition.target();
4643        if atn
4644            .state(target)
4645            .is_some_and(|target_state| target_state.kind() == AtnStateKind::LoopEnd)
4646        {
4647            if exit.replace((index, target)).is_some() {
4648                return None;
4649            }
4650        } else if enter.replace((index, target)).is_some() {
4651            return None;
4652        }
4653    }
4654    let (enter_transition_index, enter_target) = enter?;
4655    let (exit_transition_index, exit_target) = exit?;
4656    let body_stop_state = if state.kind() == AtnStateKind::StarLoopEntry {
4657        atn.state(exit_target)?.loop_back_state()?
4658    } else {
4659        state.state_number()
4660    };
4661    Some(FastRepetitionShape {
4662        enter_target,
4663        exit_target,
4664        body_stop_state,
4665        enter_transition_index,
4666        exit_transition_index,
4667    })
4668}
4669
4670fn push_fast_repetition_work(
4671    work: &mut Vec<FastRepetitionWork>,
4672    shape: FastRepetitionShape,
4673    path: FastRepetitionPath,
4674    lookahead: Option<&DecisionLookahead>,
4675    symbol: i32,
4676) {
4677    // Match the normal recognizer's FIRST-set pruning before queueing work.
4678    // Ambiguous body paths still share the coordinate bitmap below.
4679    let transition_is_viable = |transition_index: usize| {
4680        let Some(entry) = lookahead else {
4681            return true;
4682        };
4683        let Some(transition) = entry.transitions.get(transition_index) else {
4684            return true;
4685        };
4686        transition.nullable || transition.symbols.contains(symbol)
4687    };
4688    let enter_is_viable = transition_is_viable(shape.enter_transition_index);
4689    let exit_is_viable = transition_is_viable(shape.exit_transition_index);
4690    if shape.enter_transition_index < shape.exit_transition_index {
4691        if exit_is_viable {
4692            work.push(FastRepetitionWork::Exit(path));
4693        }
4694        if enter_is_viable {
4695            work.push(FastRepetitionWork::Enter(path));
4696        }
4697    } else {
4698        if enter_is_viable {
4699            work.push(FastRepetitionWork::Enter(path));
4700        }
4701        if exit_is_viable {
4702            work.push(FastRepetitionWork::Exit(path));
4703        }
4704    }
4705}
4706
4707/// Memo key for the fast recognizer. `recovery_symbols` must come from
4708/// `intern_recovery_symbols` or `empty_recovery_symbols` before it reaches this
4709/// key, so equal sets share one allocation and the key can store that
4710/// allocation's address instead of cloning an `Rc` and walking the full
4711/// `BTreeSet`. Bypassing the interner would turn content-equal recovery sets
4712/// into distinct cache coordinates.
4713#[derive(Clone, Debug)]
4714struct FastRecognizeKey {
4715    state_number: usize,
4716    stop_state: usize,
4717    index: usize,
4718    rule_start_index: usize,
4719    decision_start_index: Option<usize>,
4720    precedence: i32,
4721    recovery_symbols_id: usize,
4722    recovery_state: Option<usize>,
4723}
4724
4725impl PartialEq for FastRecognizeKey {
4726    fn eq(&self, other: &Self) -> bool {
4727        if self.state_number != other.state_number
4728            || self.stop_state != other.stop_state
4729            || self.index != other.index
4730            || self.rule_start_index != other.rule_start_index
4731            || self.decision_start_index != other.decision_start_index
4732            || self.precedence != other.precedence
4733            || self.recovery_state != other.recovery_state
4734            || self.recovery_symbols_id != other.recovery_symbols_id
4735        {
4736            return false;
4737        }
4738        true
4739    }
4740}
4741
4742impl Eq for FastRecognizeKey {}
4743
4744impl Hash for FastRecognizeKey {
4745    fn hash<H: Hasher>(&self, hasher: &mut H) {
4746        self.state_number.hash(hasher);
4747        self.stop_state.hash(hasher);
4748        self.index.hash(hasher);
4749        self.rule_start_index.hash(hasher);
4750        self.decision_start_index.hash(hasher);
4751        self.precedence.hash(hasher);
4752        self.recovery_state.hash(hasher);
4753        self.recovery_symbols_id.hash(hasher);
4754    }
4755}
4756
4757struct FastRecoveryRequest<'a, 'b> {
4758    atn: &'a Atn,
4759    transition: ParserTransition<'a>,
4760    expected_symbols: Rc<BTreeSet<i32>>,
4761    target: usize,
4762    request: FastRecognizeRequest,
4763    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4764    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4765    expected: &'b mut ExpectedTokens,
4766}
4767
4768struct FastCurrentTokenDeletionRequest<'a, 'b> {
4769    atn: &'a Atn,
4770    expected_symbols: Rc<BTreeSet<i32>>,
4771    request: FastRecognizeRequest,
4772    visiting: &'b mut FxHashSet<FastRecognizeKey>,
4773    memo: &'b mut FxHashMap<FastRecognizeKey, Rc<[FastRecognizeOutcome]>>,
4774    expected: &'b mut ExpectedTokens,
4775}
4776
4777#[derive(Clone, Copy)]
4778struct FastChildRuleFailureRecoveryRequest<'a> {
4779    atn: &'a Atn,
4780    rule_index: usize,
4781    start_index: usize,
4782    follow_state: usize,
4783    stop_state: usize,
4784    expected: &'a ExpectedTokens,
4785}
4786
4787struct RecoveryRequest<'a, 'b> {
4788    atn: &'a Atn,
4789    transition: ParserTransition<'a>,
4790    expected_symbols: BTreeSet<i32>,
4791    target: usize,
4792    request: RecognizeRequest<'a>,
4793    visiting: &'b mut BTreeSet<RecognizeKey>,
4794    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4795    expected: &'b mut ExpectedTokens,
4796}
4797
4798struct CurrentTokenDeletionRequest<'a, 'b> {
4799    atn: &'a Atn,
4800    expected_symbols: BTreeSet<i32>,
4801    request: RecognizeRequest<'a>,
4802    visiting: &'b mut BTreeSet<RecognizeKey>,
4803    memo: &'b mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
4804    expected: &'b mut ExpectedTokens,
4805}
4806
4807/// Carries the state needed after the normal token-recovery strategies fail
4808/// for a consuming transition.
4809struct ConsumingFailureFallback<'a> {
4810    atn: &'a Atn,
4811    target: usize,
4812    request: RecognizeRequest<'a>,
4813    symbol: i32,
4814    expected_symbols: BTreeSet<i32>,
4815    decision_start_index: Option<usize>,
4816    decision: Option<usize>,
4817}
4818
4819/// Captures the parent-rule context needed when a called rule fails before it
4820/// can produce a normal outcome.
4821struct ChildRuleFailureRecovery<'a> {
4822    atn: &'a Atn,
4823    rule_index: usize,
4824    start_index: usize,
4825    follow_state: usize,
4826    stop_state: usize,
4827    member_values: MemberEnv,
4828    expected: &'a ExpectedTokens,
4829}
4830
4831/// Bundles the context needed to evaluate one semantic predicate transition.
4832#[derive(Clone, Copy, Debug)]
4833struct PredicateEval<'a> {
4834    index: usize,
4835    rule_index: usize,
4836    pred_index: usize,
4837    predicates: &'a [(usize, usize, ParserPredicate)],
4838    semantics: Option<&'a ParserSemantics>,
4839    context: Option<&'a ParserRuleContext>,
4840    local_int_arg: Option<(usize, i64)>,
4841    member_values: &'a MemberEnv,
4842}
4843
4844#[derive(Clone, Copy, Debug)]
4845struct ParserSemanticHookRequest<'a> {
4846    index: usize,
4847    rule_index: usize,
4848    pred_index: usize,
4849    context: Option<&'a ParserRuleContext>,
4850    local_int_arg: Option<(usize, i64)>,
4851    member_values: &'a MemberEnv,
4852}
4853
4854/// Predicate-evaluation context over the recognizer's speculative state.
4855///
4856/// This sits in the prediction hot loop, so everything is borrowed: member
4857/// state read-only from the current speculative path and the rule name
4858/// straight from recognizer metadata. Predicates are pure by construction
4859/// ([`semir::PExpr`] has no mutating node); statement execution uses
4860/// [`ParserTableSemCtx`] (speculative member/return replay) and
4861/// [`BaseParser::parser_action_hook`] (committed action hooks) instead.
4862struct ParserSemIrCtx<'a, S, H>
4863where
4864    S: TokenSource,
4865    H: SemanticHooks,
4866{
4867    input: &'a mut CommonTokenStream<S>,
4868    tree_storage: &'a ParseTreeStorage,
4869    semantic_hooks: &'a mut H,
4870    rule_index: usize,
4871    coordinate_index: usize,
4872    rule_name: Option<&'a str>,
4873    context: Option<&'a ParserRuleContext>,
4874    local_int_arg: Option<(usize, i64)>,
4875    member_values: &'a MemberEnv,
4876    invoked_predicates: &'a mut Vec<(usize, usize)>,
4877    /// Policy applied when a [`semir::PExpr::Hook`] node's user hook declines
4878    /// (`None`); keeps the fail-loud fallback chain identical to the legacy
4879    /// table path instead of coercing the miss to `false`.
4880    unknown_predicate_policy: UnknownSemanticPolicy,
4881    unknown_predicate_hits: &'a mut Vec<(usize, usize)>,
4882}
4883
4884impl<S, H> semir::PredContext for ParserSemIrCtx<'_, S, H>
4885where
4886    S: TokenSource,
4887    H: SemanticHooks,
4888{
4889    type TokenText<'a>
4890        = TokenView<'a>
4891    where
4892        Self: 'a;
4893
4894    fn la(&mut self, offset: isize) -> i64 {
4895        i64::from(self.input.la(offset))
4896    }
4897
4898    fn token_text(&mut self, offset: isize) -> Option<Self::TokenText<'_>> {
4899        self.input.lt(offset)
4900    }
4901
4902    fn token_index_adjacent(&mut self) -> bool {
4903        let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
4904            return false;
4905        };
4906        let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
4907            return false;
4908        };
4909        first + 1 == second
4910    }
4911
4912    fn ctx_rule_text(&self, rule_index: usize) -> Option<String> {
4913        self.context.and_then(|context| {
4914            context
4915                .child_rules(self.tree_storage, self.input.token_store(), rule_index)
4916                .next()
4917                .map(crate::tree::RuleNodeView::text)
4918        })
4919    }
4920
4921    fn member(&self, member: usize) -> Option<i64> {
4922        Some(self.member_values.scalar(member).unwrap_or_default())
4923    }
4924
4925    fn member_top(&self, member: usize) -> Option<i64> {
4926        self.member_values.stack_top(member)
4927    }
4928
4929    fn member_len(&self, member: usize) -> usize {
4930        self.member_values.stack_len(member)
4931    }
4932
4933    fn local_arg(&self) -> Option<i64> {
4934        self.local_int_arg.map(|(_, value)| value)
4935    }
4936
4937    fn column(&self) -> Option<i64> {
4938        None
4939    }
4940
4941    fn token_start_column(&self) -> Option<i64> {
4942        None
4943    }
4944
4945    fn token_text_so_far(&self) -> Option<String> {
4946        None
4947    }
4948
4949    fn hook(&mut self, _hook: HookId) -> bool {
4950        let mut ctx = ParserSemCtx {
4951            input: &mut *self.input,
4952            tree_storage: self.tree_storage,
4953            rule_index: self.rule_index,
4954            coordinate_index: self.coordinate_index,
4955            rule_name: self.rule_name.map(str::to_owned),
4956            context: self.context,
4957            tree: None,
4958            local_int_arg: self.local_int_arg,
4959            member_values: self.member_values,
4960            action: None,
4961        };
4962        match self
4963            .semantic_hooks
4964            .sempred(&mut ctx, self.rule_index, self.coordinate_index)
4965        {
4966            Some(result) => result,
4967            // No hook answered this coordinate: fall through to the configured
4968            // policy instead of silently rejecting the alternative, matching the
4969            // legacy table path's dispatch chain (hook → policy).
4970            None => apply_unknown_predicate_policy(
4971                self.unknown_predicate_policy,
4972                self.rule_index,
4973                self.coordinate_index,
4974                self.unknown_predicate_hits,
4975            ),
4976        }
4977    }
4978
4979    fn trace_bool(&mut self, value: bool) -> bool {
4980        let key = (self.rule_index, self.coordinate_index);
4981        if !self.invoked_predicates.contains(&key) {
4982            self.invoked_predicates.push(key);
4983            use std::io::Write as _;
4984            let mut stdout = std::io::stdout().lock();
4985            let _ = writeln!(stdout, "eval={value}");
4986        }
4987        value
4988    }
4989}
4990
4991/// Captures predicate-failure recovery metadata for fail-option predicates.
4992struct PredicateFailureRecovery<'a> {
4993    rule_index: usize,
4994    index: usize,
4995    message: &'a str,
4996    member_values: MemberEnv,
4997    return_values: BTreeMap<String, i64>,
4998    rule_alt_number: usize,
4999}
5000
5001#[derive(Debug)]
5002enum DirectAdaptiveParseControl {
5003    Fallback(DirectAdaptiveFallback),
5004}
5005
5006#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5007enum DirectAdaptiveFallback {
5008    Action,
5009    InvalidAlt,
5010    LeftRecursiveBoundary,
5011    MissingAtn,
5012    NoTransition,
5013    Predicate,
5014    Prediction,
5015    Precedence,
5016    RuleStop,
5017    SemanticContext,
5018    StepLimit,
5019    TokenMismatch,
5020    UnknownDecision,
5021}
5022
5023type DirectAdaptiveParseResult<T> = Result<T, DirectAdaptiveParseControl>;
5024
5025struct DirectAdaptiveParser<'atn, 'sim, S, H = NoSemanticHooks>
5026where
5027    S: TokenSource,
5028    H: SemanticHooks,
5029{
5030    parser: &'sim mut BaseParser<S, H>,
5031    atn: &'atn Atn,
5032    simulator: &'sim mut ParserAtnSimulator<'atn>,
5033    decision_by_state: Vec<Option<usize>>,
5034    steps: usize,
5035}
5036
5037struct CommittedAtnParser<'atn, 'sim, 'options, S, H = NoSemanticHooks>
5038where
5039    S: TokenSource,
5040    H: SemanticHooks,
5041{
5042    parser: &'sim mut BaseParser<S, H>,
5043    atn: &'atn Atn,
5044    simulator: ParserAtnSimulator<'atn>,
5045    options: ParserRuntimeOptions<'options>,
5046    decision_by_state: Vec<Option<usize>>,
5047    action_index_by_state: FxHashMap<usize, usize>,
5048    deferred_actions: Vec<ParserAction>,
5049}
5050
5051struct CommittedRuleOutcome {
5052    tree: ParseTree,
5053    consumed_eof: bool,
5054}
5055
5056struct CommittedDecisionContext<'a> {
5057    precedence: i32,
5058    local_int_arg: Option<(usize, i64)>,
5059    context: &'a mut ParserRuleContext,
5060    entered_loops: &'a mut BTreeSet<usize>,
5061}
5062
5063/// Outcome of a generated token / set / not-set match that may recover.
5064///
5065/// Generated parsers append `children` to the current rule context. `consumed_eof`
5066/// reports whether the match actually consumed a real EOF terminal — it is true
5067/// only on a successful match (or single-token deletion that lands on EOF), and
5068/// always false on single-token insertion, which synthesizes a missing token and
5069/// consumes nothing. Generated code feeds this into `finish_rule`'s
5070/// `consumed_eof`, so the rule stop token is recorded as EOF only when EOF was
5071/// truly matched, matching ANTLR's `matchedEOF` semantics.
5072#[derive(Clone, Debug, Eq, PartialEq)]
5073pub struct GeneratedMatch {
5074    children: GeneratedMatchChildren,
5075    consumed_eof: bool,
5076}
5077
5078#[derive(Clone, Copy)]
5079enum GeneratedExpectedSymbols<'a> {
5080    Tree(&'a BTreeSet<i32>),
5081    TokenSet(ParserIntervalSet<'a>),
5082    TokenSetComplement {
5083        set: ParserIntervalSet<'a>,
5084        min_vocabulary: i32,
5085        max_vocabulary: i32,
5086    },
5087}
5088
5089impl GeneratedExpectedSymbols<'_> {
5090    fn is_empty(self) -> bool {
5091        match self {
5092            Self::Tree(symbols) => symbols.is_empty(),
5093            Self::TokenSet(set) => set.is_empty(),
5094            Self::TokenSetComplement {
5095                set,
5096                min_vocabulary,
5097                max_vocabulary,
5098            } => (min_vocabulary..=max_vocabulary).all(|symbol| set.contains(symbol)),
5099        }
5100    }
5101
5102    fn first(self) -> Option<i32> {
5103        match self {
5104            Self::Tree(symbols) => symbols.iter().next().copied(),
5105            Self::TokenSet(set) => set.ranges().next().map(|(start, _)| start),
5106            Self::TokenSetComplement {
5107                set,
5108                min_vocabulary,
5109                max_vocabulary,
5110            } => (min_vocabulary..=max_vocabulary).find(|symbol| !set.contains(*symbol)),
5111        }
5112    }
5113
5114    fn display(self, vocabulary: &Vocabulary) -> String {
5115        match self {
5116            Self::Tree(symbols) => expected_symbols_display(symbols, vocabulary),
5117            Self::TokenSet(set) => expected_symbols_display_iter(
5118                set.ranges().flat_map(|(start, stop)| start..=stop),
5119                vocabulary,
5120            ),
5121            Self::TokenSetComplement {
5122                set,
5123                min_vocabulary,
5124                max_vocabulary,
5125            } => expected_symbols_display_iter(
5126                (min_vocabulary..=max_vocabulary).filter(|symbol| !set.contains(*symbol)),
5127                vocabulary,
5128            ),
5129        }
5130    }
5131}
5132
5133#[derive(Clone, Debug, Eq, PartialEq)]
5134enum GeneratedMatchChildren {
5135    One(ParseTree),
5136    Many(Vec<ParseTree>),
5137}
5138
5139struct GeneratedMatchChildrenIntoIter {
5140    one: Option<ParseTree>,
5141    many: Option<std::vec::IntoIter<ParseTree>>,
5142}
5143
5144impl Iterator for GeneratedMatchChildrenIntoIter {
5145    type Item = ParseTree;
5146
5147    fn next(&mut self) -> Option<Self::Item> {
5148        self.one
5149            .take()
5150            .or_else(|| self.many.as_mut().and_then(Iterator::next))
5151    }
5152}
5153
5154impl GeneratedMatch {
5155    /// Parse-tree children produced by the match (the matched terminal, an
5156    /// error node plus deleted-then-matched terminal, or a single missing-token
5157    /// error node).
5158    #[must_use]
5159    pub fn children(&self) -> &[ParseTree] {
5160        match &self.children {
5161            GeneratedMatchChildren::One(child) => std::slice::from_ref(child),
5162            GeneratedMatchChildren::Many(children) => children,
5163        }
5164    }
5165
5166    /// Consumes the result, returning the children for appending to the rule
5167    /// context.
5168    #[must_use]
5169    pub fn into_children(self) -> Vec<ParseTree> {
5170        match self.children {
5171            GeneratedMatchChildren::One(child) => vec![child],
5172            GeneratedMatchChildren::Many(children) => children,
5173        }
5174    }
5175
5176    /// Consumes the match without allocating for the common single-child case.
5177    pub fn into_child_iter(self) -> impl Iterator<Item = ParseTree> {
5178        match self.children {
5179            GeneratedMatchChildren::One(child) => GeneratedMatchChildrenIntoIter {
5180                one: Some(child),
5181                many: None,
5182            },
5183            GeneratedMatchChildren::Many(children) => GeneratedMatchChildrenIntoIter {
5184                one: None,
5185                many: Some(children.into_iter()),
5186            },
5187        }
5188    }
5189
5190    /// Whether a real EOF terminal was consumed by this match.
5191    #[must_use]
5192    pub const fn consumed_eof(&self) -> bool {
5193        self.consumed_eof
5194    }
5195}
5196
5197impl<S> BaseParser<S, NoSemanticHooks>
5198where
5199    S: TokenSource,
5200{
5201    /// Creates a parser base over a buffered token stream and recognizer
5202    /// metadata.
5203    pub fn new(input: CommonTokenStream<S>, data: RecognizerData) -> Self {
5204        Self::with_semantic_hooks(input, data, NoSemanticHooks)
5205    }
5206}
5207
5208impl<S, H> BaseParser<S, H>
5209where
5210    S: TokenSource,
5211    H: SemanticHooks,
5212{
5213    /// Creates a parser base with caller-owned semantic hooks.
5214    pub fn with_semantic_hooks(
5215        input: CommonTokenStream<S>,
5216        data: RecognizerData,
5217        semantic_hooks: H,
5218    ) -> Self {
5219        Self {
5220            input,
5221            tree: ParseTreeStorage::new(),
5222            data,
5223            semantic_hooks,
5224            decision_override_generation: 0,
5225            build_parse_trees: true,
5226            syntax_errors: 0,
5227            report_diagnostic_errors: false,
5228            prediction_mode: PredictionMode::Ll,
5229            prediction_diagnostics: Vec::new(),
5230            reported_prediction_diagnostics: BTreeSet::new(),
5231            generated_parser_diagnostics: Vec::new(),
5232            generated_sync_expected: None,
5233            generated_recovery_error_index: None,
5234            generated_recovery_error_states: BTreeSet::new(),
5235            int_members: MemberEnv::new(),
5236            rule_context_stack: Vec::new(),
5237            rule_context_version: 0,
5238            left_recursive_caller_overlap_cache: std::array::from_fn(|_| None),
5239            pending_invoking_states: Vec::new(),
5240            precedence_stack: vec![0],
5241            invoked_predicates: Vec::new(),
5242            bail_on_error: false,
5243            parse_listeners: Vec::new(),
5244            parse_listener_abort: None,
5245            max_rule_depth: None,
5246            rule_depth_error: None,
5247            recursion_expansions: 0,
5248            recursion_expansion_marks: Vec::new(),
5249            unknown_predicate_policy: UnknownSemanticPolicy::default(),
5250            unknown_predicate_hits: Vec::new(),
5251            unhandled_action_hits: Vec::new(),
5252            rule_first_set_cache: Vec::new(),
5253            state_expected_cache: FxHashMap::default(),
5254            state_expected_token_cache: FxHashMap::default(),
5255            rule_stop_reach_cache: Vec::new(),
5256            recovery_symbols_intern: FxHashMap::default(),
5257            decision_lookahead_cache: FxHashMap::default(),
5258            ll1_decision_cache: FxHashMap::default(),
5259            fast_predicate_cache: FxHashMap::default(),
5260            empty_cycle_cache: Vec::new(),
5261            empty_cycle_cache_atn: None,
5262            clean_memo_mode: CleanMemoMode::Probe,
5263            clean_memo_probe_seen: FxHashSet::default(),
5264            clean_memo_probe_samples: 0,
5265            clean_memo_probe_repeats: 0,
5266            clean_memo_sparse_samples: 0,
5267            fast_recognize_scratch: FastRecognizeTopScratch::default(),
5268            fast_outcome_dedup: FastOutcomeDedupScratch::default(),
5269            empty_recovery_symbols: Rc::new(BTreeSet::new()),
5270            fast_first_set_prefilter: true,
5271            fast_recovery_enabled: true,
5272            fast_token_nodes_enabled: true,
5273            fast_track_alt_numbers: false,
5274            recognition_arena: RecognitionArena::default(),
5275            last_recognition_arena_root: NodeSeqId::EMPTY,
5276            last_recognition_arena_diagnostics: DiagnosticSeqId::EMPTY,
5277        }
5278    }
5279
5280    pub const fn input(&mut self) -> &mut CommonTokenStream<S> {
5281        &mut self.input
5282    }
5283
5284    /// Fully resets parser-owned state and rewinds the current token stream.
5285    ///
5286    /// Parser configuration, semantic hooks, learned DFA tables, and
5287    /// grammar-owned member values are retained.
5288    pub fn reset(&mut self) {
5289        self.input.seek(0);
5290        self.tree.reset();
5291        self.data.set_state(-1);
5292        self.syntax_errors = 0;
5293        self.prediction_diagnostics.clear();
5294        self.reported_prediction_diagnostics.clear();
5295        self.generated_parser_diagnostics.clear();
5296        self.generated_sync_expected = None;
5297        self.reset_generated_recovery_state();
5298        self.rule_context_stack.clear();
5299        self.advance_rule_context_version();
5300        self.left_recursive_caller_overlap_cache = std::array::from_fn(|_| None);
5301        self.pending_invoking_states.clear();
5302        self.precedence_stack.clear();
5303        self.precedence_stack.push(0);
5304        self.invoked_predicates.clear();
5305        self.decision_override_generation = 0;
5306        self.unknown_predicate_hits.clear();
5307        self.unhandled_action_hits.clear();
5308        self.parse_listener_abort = None;
5309        self.rule_depth_error = None;
5310        self.recursion_expansions = 0;
5311        self.recursion_expansion_marks.clear();
5312        self.reset_per_parse_caches();
5313        self.fast_first_set_prefilter = true;
5314        self.fast_recovery_enabled = true;
5315        self.fast_token_nodes_enabled = self.build_parse_trees;
5316        self.fast_track_alt_numbers = false;
5317        self.reset_recognition_arena();
5318    }
5319
5320    /// Replaces the buffered token stream and fully resets this parser.
5321    pub fn set_token_stream(&mut self, input: CommonTokenStream<S>) {
5322        self.input = input;
5323        self.reset();
5324    }
5325
5326    /// Installs the policy for predicate coordinates that no translated table
5327    /// entry or user hook resolves.
5328    ///
5329    /// The interpreter fallback sets this per parse from [`ParserRuntimeOptions`],
5330    /// but generated recursive-descent rules evaluate predicates directly
5331    /// (`parser_semantic_ir_predicate_matches_with_context_and_local`) without
5332    /// going through those options. Generated parser constructors call this so
5333    /// the generated-direct path honors `--sem-unknown` too, instead of leaving
5334    /// the field at its `AssumeTrue` default and silently accepting an
5335    /// unimplemented hook predicate.
5336    pub const fn set_unknown_predicate_policy(&mut self, policy: UnknownSemanticPolicy) {
5337        self.unknown_predicate_policy = policy;
5338    }
5339
5340    /// Reports any unknown predicate coordinate the generated-direct path
5341    /// recorded under [`UnknownSemanticPolicy::Error`], as an
5342    /// [`AntlrError::Unsupported`]. Generated parser entry points call this
5343    /// after a rule completes so the fail-loud policy surfaces on the
5344    /// generated path the same way the interpreter entry surfaces it.
5345    #[must_use]
5346    pub fn take_unknown_semantic_error(&mut self) -> Option<AntlrError> {
5347        let error = self.unknown_semantic_error();
5348        self.unknown_predicate_hits.clear();
5349        self.unhandled_action_hits.clear();
5350        error
5351    }
5352
5353    /// Drops any fail-loud semantic coordinates recorded by a previous parse.
5354    ///
5355    /// Generated parsers call this at the true top-level entry so a parser
5356    /// reused after a fail-loud (or recovered) parse starts clean, without
5357    /// clearing hits mid-parse where a generated parent still needs a child's
5358    /// recorded coordinate to survive to the top-level boundary.
5359    pub fn reset_unknown_semantic_hits(&mut self) {
5360        self.unknown_predicate_hits.clear();
5361        self.unhandled_action_hits.clear();
5362    }
5363
5364    /// Returns the token stream owned by this parser.
5365    #[must_use]
5366    pub const fn token_stream(&self) -> &CommonTokenStream<S> {
5367        &self.input
5368    }
5369
5370    /// Returns the token stream for source replacement or in-place re-feeding.
5371    #[must_use]
5372    pub const fn token_stream_mut(&mut self) -> &mut CommonTokenStream<S> {
5373        &mut self.input
5374    }
5375
5376    /// Returns the canonical token store referenced by parse trees.
5377    #[must_use]
5378    pub const fn token_store(&self) -> &TokenStore {
5379        self.input.token_store()
5380    }
5381
5382    /// Returns the flat CST storage populated by completed rules.
5383    #[must_use]
5384    pub const fn parse_tree_storage(&self) -> &ParseTreeStorage {
5385        &self.tree
5386    }
5387
5388    /// Resolves a compact parse-tree ID into a borrowing node view.
5389    #[must_use]
5390    pub fn node(&self, id: NodeId) -> Node<'_> {
5391        self.tree
5392            .node(self.input.token_store(), id)
5393            .expect("parser-produced node ID should remain valid")
5394    }
5395
5396    /// Consumes this parser and returns its token stream.
5397    #[must_use]
5398    pub fn into_token_stream(self) -> CommonTokenStream<S> {
5399        self.input
5400    }
5401
5402    /// Consumes this parser and returns its canonical token store.
5403    #[must_use]
5404    pub fn into_token_store(self) -> TokenStore {
5405        self.input.into_token_store()
5406    }
5407
5408    /// Consumes the parser and pairs its token store and flat CST with `root`.
5409    #[must_use]
5410    pub fn into_parsed_file(self, root: NodeId) -> ParsedFile {
5411        ParsedFile::new(self.input.into_token_store(), self.tree, root)
5412    }
5413
5414    /// Returns the number of parser syntax errors recorded by committed parse
5415    /// paths so far.
5416    pub const fn number_of_syntax_errors(&self) -> usize {
5417        self.syntax_errors
5418    }
5419
5420    /// Computes reachability and retained-capacity counters for the most recent
5421    /// interpreted-rule recognition arena.
5422    ///
5423    /// The reachability scan is linear in the arena size and is deferred until
5424    /// this instrumentation method is called.
5425    #[must_use]
5426    pub fn recognition_arena_stats(&self) -> RecognitionArenaStats {
5427        self.recognition_arena.stats(
5428            self.last_recognition_arena_root,
5429            self.last_recognition_arena_diagnostics,
5430        )
5431    }
5432
5433    /// Records a syntax error that generated parser code returns as fatal before
5434    /// it can recover into the current rule context.
5435    pub const fn record_generated_syntax_error(&mut self) {
5436        self.record_syntax_errors(1);
5437    }
5438
5439    const fn record_syntax_errors(&mut self, count: usize) {
5440        self.syntax_errors = self.syntax_errors.saturating_add(count);
5441    }
5442
5443    /// Returns whether no interpreted rule context or generated invocation is active.
5444    const fn is_top_level_entry(&self) -> bool {
5445        self.rule_context_stack.is_empty() && self.pending_invoking_states.is_empty()
5446    }
5447
5448    /// Emits diagnostics buffered by the token stream while generated parser
5449    /// code was fetching lexer tokens directly.
5450    pub fn report_token_source_errors(&mut self) {
5451        let errors = self.input.drain_source_errors();
5452        self.dispatch_token_source_errors(&errors);
5453    }
5454
5455    /// Captures generated-parser diagnostics and syntax-error count before a
5456    /// speculative generated rule path.
5457    pub const fn generated_diagnostics_checkpoint(&self) -> GeneratedDiagnosticsCheckpoint {
5458        GeneratedDiagnosticsCheckpoint {
5459            diagnostics_len: self.generated_parser_diagnostics.len(),
5460            syntax_errors: self.syntax_errors,
5461            tree: self.tree.checkpoint(),
5462        }
5463    }
5464
5465    /// Restores generated-parser diagnostics after a speculative rule path failed.
5466    pub fn restore_generated_diagnostics(&mut self, marker: GeneratedDiagnosticsCheckpoint) {
5467        self.generated_parser_diagnostics
5468            .truncate(marker.diagnostics_len);
5469        self.syntax_errors = marker.syntax_errors;
5470        self.rollback_generated_tree(marker);
5471    }
5472
5473    /// Rolls back generated tree state while retaining committed diagnostics.
5474    ///
5475    /// Fatal public entries use this after an earlier child recovery: the
5476    /// partial tree is discarded, but ANTLR has already committed the child's
5477    /// diagnostic and syntax-error count.
5478    pub fn rollback_generated_tree(&mut self, marker: GeneratedDiagnosticsCheckpoint) {
5479        self.generated_sync_expected = None;
5480        self.tree.rollback(marker.tree);
5481    }
5482
5483    /// Emits diagnostics recorded by committed generated parser recovery.
5484    pub fn report_generated_parser_diagnostics(&mut self) {
5485        let parser_diagnostics = std::mem::take(&mut self.generated_parser_diagnostics);
5486        let token_errors = self.input.drain_source_errors();
5487        self.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
5488    }
5489
5490    fn syntax_error_event<'a>(
5491        &'a self,
5492        offending: Option<TokenId>,
5493        line: usize,
5494        column: usize,
5495        message: &'a str,
5496        error: Option<&'a AntlrError>,
5497    ) -> SyntaxErrorEvent<'a> {
5498        let offending = offending.and_then(|token| self.token_store().view(token));
5499        SyntaxErrorEvent {
5500            offending,
5501            line,
5502            column,
5503            span: offending.and_then(|token| token.byte_span()),
5504            message,
5505            error,
5506        }
5507    }
5508
5509    /// Emits a fatal parser error after an entry-rule parse commits to returning it.
5510    ///
5511    /// Generated parsers call this only at their public entry boundary. Nested
5512    /// failures remain silent until generated recovery commits and buffers them.
5513    pub fn report_unrecovered_parser_error(&self, error: &AntlrError) {
5514        let AntlrError::ParserError {
5515            line,
5516            column,
5517            message,
5518            offending,
5519        } = error
5520        else {
5521            return;
5522        };
5523        self.notify_error_listeners(self.syntax_error_event(
5524            *offending,
5525            *line,
5526            *column,
5527            message,
5528            Some(error),
5529        ));
5530    }
5531
5532    fn dispatch_parser_diagnostic(&self, diagnostic: &ParserDiagnostic) {
5533        self.notify_error_listeners(self.syntax_error_event(
5534            diagnostic.offending,
5535            diagnostic.line,
5536            diagnostic.column,
5537            &diagnostic.message,
5538            None,
5539        ));
5540    }
5541
5542    fn dispatch_parser_diagnostics<'a>(
5543        &self,
5544        diagnostics: impl IntoIterator<Item = &'a ParserDiagnostic>,
5545    ) {
5546        for diagnostic in diagnostics {
5547            self.dispatch_parser_diagnostic(diagnostic);
5548        }
5549    }
5550
5551    fn dispatch_token_source_error(&self, source_error: &TokenSourceError) {
5552        if self.input.token_source().report_error(source_error) {
5553            return;
5554        }
5555        // Lexer errors have no offending token: the failure is that no token
5556        // could be produced, matching ANTLR's null offendingSymbol.
5557        self.notify_error_listeners(source_error.into());
5558    }
5559
5560    fn dispatch_token_source_errors(&self, errors: &[TokenSourceError]) {
5561        for error in errors {
5562            self.dispatch_token_source_error(error);
5563        }
5564    }
5565
5566    /// Dispatches generated parser and lexer diagnostics in the same
5567    /// source-position order as ANTLR's lazy token stream reports them.
5568    fn dispatch_generated_diagnostics(
5569        &self,
5570        parser_diagnostics: &[ParserDiagnostic],
5571        token_errors: &[TokenSourceError],
5572    ) {
5573        // Parser diagnostics keep their event order: Java's console and
5574        // DiagnosticErrorListener print reports as prediction produces them,
5575        // so reportAttemptingFullContext precedes reportContextSensitivity
5576        // even though the latter's position is earlier. Buffered token-source
5577        // errors interleave by source position and win ties.
5578        let mut token_iter = token_errors.iter().peekable();
5579        for diagnostic in parser_diagnostics {
5580            while let Some(error) = token_iter.peek() {
5581                if (error.line, error.column) <= (diagnostic.line, diagnostic.column) {
5582                    self.dispatch_token_source_error(error);
5583                    token_iter.next();
5584                } else {
5585                    break;
5586                }
5587            }
5588            self.dispatch_parser_diagnostic(diagnostic);
5589        }
5590        for error in token_iter {
5591            self.dispatch_token_source_error(error);
5592        }
5593    }
5594
5595    /// Buffers ANTLR-style ambiguity diagnostics discovered by generated
5596    /// decision code.
5597    pub fn record_generated_ambiguity_diagnostic(
5598        &mut self,
5599        atn: &Atn,
5600        state_number: usize,
5601        start_index: usize,
5602        stop_index: usize,
5603        alts: &[usize],
5604    ) {
5605        if !self.report_diagnostic_errors || alts.len() < 2 {
5606            return;
5607        }
5608        let Some(decision) = atn
5609            .decision_to_state()
5610            .iter()
5611            .position(|candidate| candidate == state_number)
5612        else {
5613            return;
5614        };
5615        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5616            return;
5617        };
5618        let rule_name = self
5619            .rule_names()
5620            .get(rule_index)
5621            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5622        let input = display_input_text(&self.input.text(start_index, stop_index));
5623        let alts = alts
5624            .iter()
5625            .map(usize::to_string)
5626            .collect::<Vec<_>>()
5627            .join(", ");
5628        let key = (decision, start_index, format!("{alts}:{input}"));
5629        if !self.reported_prediction_diagnostics.insert(key) {
5630            return;
5631        }
5632        let start_diagnostic = diagnostic_for_token(
5633            self.token_at(start_index),
5634            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
5635        );
5636        let stop_diagnostic = diagnostic_for_token(
5637            self.token_at(stop_index),
5638            format!(
5639                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
5640            ),
5641        );
5642        self.generated_parser_diagnostics.push(start_diagnostic);
5643        self.generated_parser_diagnostics.push(stop_diagnostic);
5644    }
5645
5646    /// Buffers ANTLR-style diagnostic-listener messages produced by generated
5647    /// parser calls to the adaptive simulator.
5648    pub fn record_generated_prediction_diagnostic(
5649        &mut self,
5650        atn: &Atn,
5651        state_number: usize,
5652        prediction: &ParserAtnPrediction,
5653    ) {
5654        if self.prediction_mode == PredictionMode::Sll {
5655            return;
5656        }
5657        let Some(diagnostic) = &prediction.diagnostic else {
5658            return;
5659        };
5660        if !self.report_diagnostic_errors || diagnostic.conflicting_alts.len() < 2 {
5661            return;
5662        }
5663        let Some(decision) = atn
5664            .decision_to_state()
5665            .iter()
5666            .position(|candidate| candidate == state_number)
5667        else {
5668            return;
5669        };
5670        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5671            return;
5672        };
5673        let rule_name = self
5674            .rule_names()
5675            .get(rule_index)
5676            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5677        let attempt_input = display_input_text(
5678            &self
5679                .input
5680                .text(diagnostic.start_index, diagnostic.sll_stop_index),
5681        );
5682        let result_input = display_input_text(
5683            &self
5684                .input
5685                .text(diagnostic.start_index, diagnostic.ll_stop_index),
5686        );
5687        let alts = diagnostic
5688            .conflicting_alts
5689            .iter()
5690            .map(usize::to_string)
5691            .collect::<Vec<_>>()
5692            .join(", ");
5693        let key = (
5694            decision,
5695            diagnostic.start_index,
5696            format!(
5697                "{:?}:{alts}:{attempt_input}:{result_input}",
5698                diagnostic.kind
5699            ),
5700        );
5701        if !self.reported_prediction_diagnostics.insert(key) {
5702            return;
5703        }
5704        let local_exact_ambiguity = !prediction.requires_full_context
5705            && diagnostic.kind == ParserAtnPredictionDiagnosticKind::Ambiguity
5706            && diagnostic.exact;
5707        if !local_exact_ambiguity {
5708            let attempt_diagnostic = diagnostic_for_token(
5709                self.token_at(diagnostic.sll_stop_index),
5710                format!(
5711                    "reportAttemptingFullContext d={decision} ({rule_name}), input='{attempt_input}'"
5712                ),
5713            );
5714            self.generated_parser_diagnostics.push(attempt_diagnostic);
5715        }
5716        let message = match diagnostic.kind {
5717            ParserAtnPredictionDiagnosticKind::Ambiguity => {
5718                // Java's DiagnosticErrorListener is exactOnly by default:
5719                // non-exact ambiguities (default LL mode stopping at the
5720                // first resolvable conflict) report the attempt above but
5721                // suppress the ambiguity line itself.
5722                if !diagnostic.exact {
5723                    return;
5724                }
5725                format!(
5726                    "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{result_input}'"
5727                )
5728            }
5729            ParserAtnPredictionDiagnosticKind::ContextSensitivity => {
5730                format!(
5731                    "reportContextSensitivity d={decision} ({rule_name}), input='{result_input}'"
5732                )
5733            }
5734        };
5735        let result_diagnostic =
5736            diagnostic_for_token(self.token_at(diagnostic.ll_stop_index), message);
5737        self.generated_parser_diagnostics.push(result_diagnostic);
5738    }
5739
5740    pub fn la(&self, offset: isize) -> i32 {
5741        self.input.la_token(offset)
5742    }
5743
5744    pub fn consume(&mut self) {
5745        IntStream::consume(&mut self.input);
5746    }
5747
5748    /// Sets a generated integer member value used by target-template tests.
5749    pub fn set_int_member(&mut self, member: usize, value: i64) {
5750        self.int_members.set_scalar(member, value);
5751    }
5752
5753    /// Reads a generated integer member value.
5754    pub fn int_member(&self, member: usize) -> Option<i64> {
5755        self.int_members.scalar(member)
5756    }
5757
5758    /// Pushes onto a generated stack-valued member slot (issue #206).
5759    pub fn push_stack_member(&mut self, member: usize, value: i64) {
5760        self.int_members.push_stack(member, value);
5761    }
5762
5763    /// Pops a generated stack-valued member slot, returning the removed value.
5764    /// `None` when the stack is empty.
5765    pub fn pop_stack_member(&mut self, member: usize) -> Option<i64> {
5766        self.int_members.pop_stack(member)
5767    }
5768
5769    /// Reads the top of a generated stack-valued member slot; `None` when
5770    /// empty or never pushed.
5771    #[must_use]
5772    pub fn stack_member_top(&self, member: usize) -> Option<i64> {
5773        self.int_members.stack_top(member)
5774    }
5775
5776    /// Depth of a generated stack-valued member slot.
5777    #[must_use]
5778    pub fn stack_member_len(&self, member: usize) -> usize {
5779        self.int_members.stack_len(member)
5780    }
5781
5782    /// Seeds grammar-declared initial member values (issue #206).
5783    ///
5784    /// Generated parsers call this at construction for a grammar whose
5785    /// `@members` declares an initializer (`private int level = 1;`). Without
5786    /// it the slot would start at 0, so a predicate reading it would reject
5787    /// input the source grammar accepts.
5788    pub fn set_initial_members(&mut self, initial: impl IntoIterator<Item = (usize, i64)>) {
5789        self.int_members = MemberEnv::with_initial_scalars(initial);
5790    }
5791
5792    /// Captures generated member state before speculative generated parser
5793    /// execution.
5794    ///
5795    /// The snapshot covers scalar *and* stack slots: restoring only scalars
5796    /// would leave a rolled-back path's pushes behind.
5797    #[must_use]
5798    pub fn int_members_checkpoint(&self) -> MemberEnv {
5799        self.int_members.clone()
5800    }
5801
5802    /// Restores generated member state after generated parser fallback.
5803    pub fn restore_int_members(&mut self, members: MemberEnv) {
5804        self.int_members = members;
5805    }
5806
5807    /// Adds `delta` to a generated integer member and returns the new value.
5808    pub fn add_int_member(&mut self, member: usize, delta: i64) -> i64 {
5809        self.int_members.add_scalar(member, delta)
5810    }
5811
5812    fn token_type_for_id(&self, id: TokenId) -> i32 {
5813        self.input.token_store().token_type(id).unwrap_or(TOKEN_EOF)
5814    }
5815
5816    fn terminal_tree(&mut self, id: TokenId) -> ParseTree {
5817        if self.build_parse_trees {
5818            self.tree.terminal(id)
5819        } else {
5820            NodeId::placeholder()
5821        }
5822    }
5823
5824    fn error_tree(&mut self, id: TokenId) -> ParseTree {
5825        if self.build_parse_trees {
5826            self.tree.error(id)
5827        } else {
5828            NodeId::placeholder()
5829        }
5830    }
5831
5832    const fn set_context_start(&self, context: &mut ParserRuleContext, id: TokenId) {
5833        context.set_start_id(id);
5834    }
5835
5836    const fn set_context_stop(&self, context: &mut ParserRuleContext, id: TokenId) {
5837        context.set_stop_id(id);
5838    }
5839
5840    fn insert_synthetic_token(
5841        &mut self,
5842        token_type: i32,
5843        text: String,
5844        line: usize,
5845        column: usize,
5846    ) -> Result<TokenId, AntlrError> {
5847        self.input
5848            .insert(
5849                TokenSpec::explicit(token_type, text)
5850                    .with_span(usize::MAX, usize::MAX)
5851                    .with_position(line, column),
5852            )
5853            .map_err(|error| AntlrError::Unsupported(error.to_string()))
5854    }
5855
5856    /// Matches and consumes the current token when it has the expected token
5857    /// type.
5858    ///
5859    /// On success the consumed token is wrapped as a terminal parse-tree node.
5860    /// On mismatch the error carries vocabulary display names so diagnostics are
5861    /// stable across literal and symbolic token naming.
5862    pub fn match_token(&mut self, token_type: i32) -> Result<ParseTree, AntlrError> {
5863        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5864            line: 0,
5865            column: 0,
5866            message: "missing current token".to_owned(),
5867            offending: None,
5868        })?;
5869        let current_type = self.token_type_for_id(current);
5870        if current_type == token_type {
5871            self.reset_generated_recovery_state();
5872            self.consume();
5873            Ok(self.terminal_tree(current))
5874        } else {
5875            Err(AntlrError::MismatchedInput {
5876                expected: self.vocabulary().display_name(token_type),
5877                found: self.vocabulary().display_name(current_type),
5878            })
5879        }
5880    }
5881
5882    /// Matches a token from generated recursive-descent code, including ANTLR's
5883    /// single-token insertion recovery when the active rule context can legally
5884    /// continue at the current input symbol.
5885    pub fn match_token_recovering(
5886        &mut self,
5887        token_type: i32,
5888        follow_state: usize,
5889        atn: &Atn,
5890    ) -> Result<GeneratedMatch, AntlrError> {
5891        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5892            line: 0,
5893            column: 0,
5894            message: "missing current token".to_owned(),
5895            offending: None,
5896        })?;
5897        let current_type = self.token_type_for_id(current);
5898        if current_type == token_type {
5899            self.generated_sync_expected = None;
5900            self.reset_generated_recovery_state();
5901            let consumed_eof = current_type == TOKEN_EOF;
5902            self.consume();
5903            return Ok(GeneratedMatch {
5904                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5905                consumed_eof,
5906            });
5907        }
5908        let mut expected_symbols = BTreeSet::new();
5909        expected_symbols.insert(token_type);
5910        self.recover_generated_match(
5911            current,
5912            GeneratedExpectedSymbols::Tree(&expected_symbols),
5913            follow_state,
5914            atn,
5915            |symbol| symbol == token_type,
5916        )
5917    }
5918
5919    pub fn match_set_recovering(
5920        &mut self,
5921        intervals: &[(i32, i32)],
5922        follow_state: usize,
5923        atn: &Atn,
5924    ) -> Result<GeneratedMatch, AntlrError> {
5925        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5926            line: 0,
5927            column: 0,
5928            message: "missing current token".to_owned(),
5929            offending: None,
5930        })?;
5931        let current_type = self.token_type_for_id(current);
5932        if interval_set_contains(intervals, current_type) {
5933            self.generated_sync_expected = None;
5934            self.reset_generated_recovery_state();
5935            let consumed_eof = current_type == TOKEN_EOF;
5936            self.consume();
5937            return Ok(GeneratedMatch {
5938                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5939                consumed_eof,
5940            });
5941        }
5942        let expected_symbols = interval_symbols(intervals);
5943        self.recover_generated_match(
5944            current,
5945            GeneratedExpectedSymbols::Tree(&expected_symbols),
5946            follow_state,
5947            atn,
5948            |symbol| interval_set_contains(intervals, symbol),
5949        )
5950    }
5951
5952    pub fn match_token_set_recovering(
5953        &mut self,
5954        set: ParserIntervalSet<'_>,
5955        follow_state: usize,
5956        atn: &Atn,
5957    ) -> Result<GeneratedMatch, AntlrError> {
5958        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5959            line: 0,
5960            column: 0,
5961            message: "missing current token".to_owned(),
5962            offending: None,
5963        })?;
5964        let current_type = self.token_type_for_id(current);
5965        if set.contains(current_type) {
5966            self.generated_sync_expected = None;
5967            self.reset_generated_recovery_state();
5968            let consumed_eof = current_type == TOKEN_EOF;
5969            self.consume();
5970            return Ok(GeneratedMatch {
5971                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5972                consumed_eof,
5973            });
5974        }
5975        self.recover_generated_match(
5976            current,
5977            GeneratedExpectedSymbols::TokenSet(set),
5978            follow_state,
5979            atn,
5980            |symbol| set.contains(symbol),
5981        )
5982    }
5983
5984    pub fn match_not_set_recovering(
5985        &mut self,
5986        intervals: &[(i32, i32)],
5987        min_vocabulary: i32,
5988        max_vocabulary: i32,
5989        follow_state: usize,
5990        atn: &Atn,
5991    ) -> Result<GeneratedMatch, AntlrError> {
5992        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5993            line: 0,
5994            column: 0,
5995            message: "missing current token".to_owned(),
5996            offending: None,
5997        })?;
5998        let current_type = self.token_type_for_id(current);
5999        if (min_vocabulary..=max_vocabulary).contains(&current_type)
6000            && !interval_set_contains(intervals, current_type)
6001        {
6002            self.generated_sync_expected = None;
6003            self.reset_generated_recovery_state();
6004            let consumed_eof = current_type == TOKEN_EOF;
6005            self.consume();
6006            return Ok(GeneratedMatch {
6007                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
6008                consumed_eof,
6009            });
6010        }
6011        let expected_symbols =
6012            interval_complement_symbols(intervals, min_vocabulary, max_vocabulary);
6013        self.recover_generated_match(
6014            current,
6015            GeneratedExpectedSymbols::Tree(&expected_symbols),
6016            follow_state,
6017            atn,
6018            |symbol| {
6019                (min_vocabulary..=max_vocabulary).contains(&symbol)
6020                    && !interval_set_contains(intervals, symbol)
6021            },
6022        )
6023    }
6024
6025    pub fn match_not_token_set_recovering(
6026        &mut self,
6027        set: ParserIntervalSet<'_>,
6028        min_vocabulary: i32,
6029        max_vocabulary: i32,
6030        follow_state: usize,
6031        atn: &Atn,
6032    ) -> Result<GeneratedMatch, AntlrError> {
6033        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6034            line: 0,
6035            column: 0,
6036            message: "missing current token".to_owned(),
6037            offending: None,
6038        })?;
6039        let current_type = self.token_type_for_id(current);
6040        if (min_vocabulary..=max_vocabulary).contains(&current_type) && !set.contains(current_type)
6041        {
6042            self.generated_sync_expected = None;
6043            self.reset_generated_recovery_state();
6044            let consumed_eof = current_type == TOKEN_EOF;
6045            self.consume();
6046            return Ok(GeneratedMatch {
6047                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
6048                consumed_eof,
6049            });
6050        }
6051        self.recover_generated_match(
6052            current,
6053            GeneratedExpectedSymbols::TokenSetComplement {
6054                set,
6055                min_vocabulary,
6056                max_vocabulary,
6057            },
6058            follow_state,
6059            atn,
6060            |symbol| (min_vocabulary..=max_vocabulary).contains(&symbol) && !set.contains(symbol),
6061        )
6062    }
6063
6064    fn recover_generated_match(
6065        &mut self,
6066        current: TokenId,
6067        expected_symbols: GeneratedExpectedSymbols<'_>,
6068        follow_state: usize,
6069        atn: &Atn,
6070        matches: impl Fn(i32) -> bool,
6071    ) -> Result<GeneratedMatch, AntlrError> {
6072        let expected_display = expected_symbols.display(self.vocabulary());
6073        let (current_type, current_line, current_column, current_display) = {
6074            let token = self
6075                .input
6076                .token_view(current)
6077                .expect("current token ID should be valid");
6078            (
6079                token.token_type(),
6080                token.line(),
6081                token.column(),
6082                token_input_display(&token),
6083            )
6084        };
6085        if self.bail_on_error {
6086            return Err(AntlrError::ParserError {
6087                line: current_line,
6088                column: current_column,
6089                message: format!("mismatched input {current_display} expecting {expected_display}"),
6090                offending: Some(current),
6091            });
6092        }
6093        if current_type != TOKEN_EOF
6094            && let Some(next) = self.input.lt_id(2)
6095            && matches(self.token_type_for_id(next))
6096        {
6097            let message =
6098                format!("extraneous input {current_display} expecting {expected_display}");
6099            self.push_generated_parser_diagnostic(ParserDiagnostic {
6100                line: current_line,
6101                column: current_column,
6102                message,
6103                offending: Some(current),
6104            });
6105            self.record_syntax_errors(1);
6106            self.generated_sync_expected = None;
6107            // Single-token deletion: skip `current`, then accept `next`. The
6108            // accepted token can be EOF only if it is a real EOF terminal.
6109            let consumed_eof = self.token_type_for_id(next) == TOKEN_EOF;
6110            self.consume();
6111            self.consume();
6112            self.reset_generated_recovery_state();
6113            return Ok(GeneratedMatch {
6114                children: GeneratedMatchChildren::Many(vec![
6115                    self.error_tree(current),
6116                    self.terminal_tree(next),
6117                ]),
6118                consumed_eof,
6119            });
6120        }
6121        let follow_symbols = self.generated_recovery_follow_symbols(atn, follow_state);
6122        // ANTLR's `singleTokenInsertion` inserts a missing token when the state
6123        // *after* the current element can consume the current symbol. At EOF that
6124        // only holds when the follow state EXPLICITLY expects EOF (e.g. an `EOF`
6125        // terminal follows in the rule, as in `r: . EOF;` or `r: ID EOF;`), not
6126        // when EOF merely leaks in from the empty enclosing context (as in
6127        // `start: ID+;` on empty input — antlr#6 `InvalidEmptyInput`, which must
6128        // stay a `mismatched input` error). `follow_symbols` mixes both sources,
6129        // so consult the follow state's OWN expected set for the explicit case.
6130        let follow_explicitly_expects_eof = current_type == TOKEN_EOF
6131            && self
6132                .cached_state_expected_symbols(atn, follow_state)
6133                .contains(&TOKEN_EOF);
6134        if follow_symbols.contains(&current_type)
6135            && (current_type != TOKEN_EOF
6136                || self.rule_context_stack.len() > 1
6137                || expected_symbols.is_empty()
6138                || follow_explicitly_expects_eof)
6139        {
6140            let message = format!("missing {expected_display} at {current_display}");
6141            self.push_generated_parser_diagnostic(ParserDiagnostic {
6142                line: current_line,
6143                column: current_column,
6144                message,
6145                offending: Some(current),
6146            });
6147            self.record_syntax_errors(1);
6148            self.generated_sync_expected = None;
6149            let token_type = expected_symbols.first().unwrap_or(TOKEN_EOF);
6150            let missing_display = expected_symbol_display(token_type, self.vocabulary());
6151            let token = self.insert_synthetic_token(
6152                token_type,
6153                format!("<missing {missing_display}>"),
6154                current_line,
6155                current_column,
6156            )?;
6157            // Single-token insertion synthesizes a missing token and consumes
6158            // nothing, so no EOF terminal is consumed even when the lookahead is
6159            // EOF. Reporting consumed_eof=false here is what keeps `finish_rule`
6160            // from recording EOF as the rule stop on this recovery path.
6161            return Ok(GeneratedMatch {
6162                children: GeneratedMatchChildren::One(self.error_tree(token)),
6163                consumed_eof: false,
6164            });
6165        }
6166        let mismatch_expected_display = self
6167            .generated_sync_expected
6168            .take()
6169            .map_or(expected_display, |symbols| {
6170                expected_symbols_display_iter(symbols.symbols(), self.vocabulary())
6171            });
6172        Err(AntlrError::ParserError {
6173            line: current_line,
6174            column: current_column,
6175            message: format!(
6176                "mismatched input {current_display} expecting {mismatch_expected_display}"
6177            ),
6178            offending: Some(current),
6179        })
6180    }
6181
6182    fn generated_recovery_follow_symbols(
6183        &mut self,
6184        atn: &Atn,
6185        follow_state: usize,
6186    ) -> BTreeSet<i32> {
6187        let mut follow = self
6188            .cached_state_expected_symbols(atn, follow_state)
6189            .as_ref()
6190            .clone();
6191        if self.cached_state_can_reach_rule_stop(atn, follow_state) {
6192            follow.extend(self.context_expected_symbols(atn));
6193        }
6194        follow
6195    }
6196
6197    pub fn match_eof(&mut self) -> Result<ParseTree, AntlrError> {
6198        self.match_token(TOKEN_EOF)
6199    }
6200
6201    pub fn match_set(&mut self, intervals: &[(i32, i32)]) -> Result<ParseTree, AntlrError> {
6202        self.match_interval_condition(intervals, |symbol| interval_set_contains(intervals, symbol))
6203    }
6204
6205    pub fn match_not_set(
6206        &mut self,
6207        intervals: &[(i32, i32)],
6208        min_vocabulary: i32,
6209        max_vocabulary: i32,
6210    ) -> Result<ParseTree, AntlrError> {
6211        self.match_interval_condition(intervals, |symbol| {
6212            (min_vocabulary..=max_vocabulary).contains(&symbol)
6213                && !interval_set_contains(intervals, symbol)
6214        })
6215    }
6216
6217    fn match_interval_condition(
6218        &mut self,
6219        intervals: &[(i32, i32)],
6220        matches: impl FnOnce(i32) -> bool,
6221    ) -> Result<ParseTree, AntlrError> {
6222        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6223            line: 0,
6224            column: 0,
6225            message: "missing current token".to_owned(),
6226            offending: None,
6227        })?;
6228        let current_type = self.token_type_for_id(current);
6229        if matches(current_type) {
6230            self.reset_generated_recovery_state();
6231            self.consume();
6232            Ok(self.terminal_tree(current))
6233        } else {
6234            Err(AntlrError::MismatchedInput {
6235                expected: self.interval_display(intervals),
6236                found: self.vocabulary().display_name(current_type),
6237            })
6238        }
6239    }
6240
6241    fn interval_display(&self, intervals: &[(i32, i32)]) -> String {
6242        let values = intervals
6243            .iter()
6244            .map(|(start, stop)| {
6245                if start == stop {
6246                    self.vocabulary().display_name(*start)
6247                } else {
6248                    format!(
6249                        "{}..{}",
6250                        self.vocabulary().display_name(*start),
6251                        self.vocabulary().display_name(*stop)
6252                    )
6253                }
6254            })
6255            .collect::<Vec<_>>()
6256            .join(", ");
6257        format!("{{{values}}}")
6258    }
6259
6260    pub fn rule_node(&mut self, context: ParserRuleContext) -> ParseTree {
6261        if self.build_parse_trees {
6262            self.tree.finish_rule(context)
6263        } else {
6264            NodeId::placeholder()
6265        }
6266    }
6267
6268    /// Reports whether the generated rule dispatch should sample native stack
6269    /// capacity before descending into the next rule body.
6270    ///
6271    /// Generated recursive-descent methods otherwise map unbounded grammar
6272    /// nesting straight onto native call depth; sampling every
6273    /// [`GENERATED_RULE_STACK_CHECK_INTERVAL`] rule-context frames keeps the
6274    /// hot path free of per-call probes while guaranteeing a check runs before
6275    /// the red zone can be crossed.
6276    #[must_use]
6277    pub const fn generated_rule_stack_check_due(&self) -> bool {
6278        self.rule_context_stack
6279            .len()
6280            .is_multiple_of(GENERATED_RULE_STACK_CHECK_INTERVAL)
6281    }
6282
6283    /// Returns the positioned error to abort with when the configured
6284    /// rule-nesting depth cap would be exceeded by one more level, or `None`
6285    /// to keep parsing.
6286    ///
6287    /// Generated rule dispatch calls this before deepening — ahead of the
6288    /// rule-frame push at the dispatch boundary and ahead of each
6289    /// left-recursive expansion — letting callers parsing untrusted input
6290    /// bound CPU and tree memory ([`Parser::set_max_rule_depth`]). The
6291    /// inline fast path is one `Option` check when no cap is set (the
6292    /// default) and one addition plus compare when one is; only an actual
6293    /// violation leaves the inline path.
6294    ///
6295    /// The violation is sticky: rule-level recovery absorbs the returned
6296    /// error like any other rule failure and would otherwise keep spending
6297    /// the very resources the cap exists to bound, so every check after the
6298    /// first violation fails until [`Self::take_rule_depth_error`] drains it
6299    /// at the top-level entry.
6300    #[inline]
6301    pub fn rule_depth_cap_violation(&mut self) -> Option<AntlrError> {
6302        let max = self.max_rule_depth?;
6303        // Left-recursive operator iterations deepen the tree without pushing
6304        // a rule frame, so they count alongside the rule-context stack.
6305        if self.rule_depth_error.is_none()
6306            && self.rule_context_stack.len() + self.recursion_expansions < max
6307        {
6308            return None;
6309        }
6310        Some(self.rule_depth_cap_violation_cold(max))
6311    }
6312
6313    #[cold]
6314    fn rule_depth_cap_violation_cold(&mut self, max: usize) -> AntlrError {
6315        if let Some(error) = &self.rule_depth_error {
6316            return error.clone();
6317        }
6318        let current = self.input.lt(1);
6319        let (line, column) = current
6320            .as_ref()
6321            .map_or((0, 0), |token| (token.line(), token.column()));
6322        let error = AntlrError::ParserError {
6323            line,
6324            column,
6325            message: format!("rule nesting depth limit of {max} exceeded"),
6326            offending: current.as_ref().map(Token::token_id),
6327        };
6328        self.rule_depth_error = Some(error.clone());
6329        error
6330    }
6331
6332    /// Drains the sticky depth-cap violation recorded by
6333    /// [`Self::rule_depth_cap_violation`], if any.
6334    ///
6335    /// Generated top-level rule entries call this after recognition so a
6336    /// recovered parse that crossed the cap still fails, and so a reused
6337    /// parser starts its next parse clean.
6338    pub const fn take_rule_depth_error(&mut self) -> Option<AntlrError> {
6339        self.rule_depth_error.take()
6340    }
6341
6342    /// Reports whether a rule-nesting depth cap is configured.
6343    ///
6344    /// Generated dispatch consults this when selecting between the guarded
6345    /// recursive-descent body and the ATN-preferred interpreted fast path:
6346    /// only the generated body enforces the cap, so a configured bound
6347    /// overrides the performance preference.
6348    #[must_use]
6349    pub const fn has_rule_depth_cap(&self) -> bool {
6350        self.max_rule_depth.is_some()
6351    }
6352
6353    /// Registers a listener for committed rule enter/exit events during
6354    /// recognition (ANTLR's `addParseListener`). See [`ParseListener`] for
6355    /// the delivery contract.
6356    pub fn add_parse_listener<L>(&mut self, listener: L)
6357    where
6358        L: ParseListener + 'static,
6359    {
6360        self.parse_listeners
6361            .push(ParseListenerSlot(Box::new(listener)));
6362    }
6363
6364    /// Removes every registered parse listener and returns them, dropping any
6365    /// sticky abort a removed listener had requested.
6366    ///
6367    /// Returning the boxed listeners gives callers back the state they
6368    /// accumulated (depth counters, collected events) without threading
6369    /// shared handles through the listener.
6370    pub fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
6371        self.parse_listener_abort = None;
6372        self.parse_listeners.drain(..).map(|slot| slot.0).collect()
6373    }
6374
6375    /// Reports whether any parse listener is registered.
6376    ///
6377    /// Generated dispatch consults this alongside [`Self::has_rule_depth_cap`]
6378    /// when choosing between the generated body (which fires events) and the
6379    /// ATN-preferred interpreted fast path (which does not).
6380    #[must_use]
6381    pub const fn has_parse_listeners(&self) -> bool {
6382        !self.parse_listeners.is_empty()
6383    }
6384
6385    /// Reports whether semantic hooks may override interpreted decisions.
6386    ///
6387    /// Generated parsers use this to keep adaptive performance routing from
6388    /// changing parse semantics after a decision DFA becomes warm.
6389    #[doc(hidden)]
6390    #[must_use]
6391    pub fn observes_parser_decisions(&self) -> bool {
6392        self.semantic_hooks.observes_parser_decisions()
6393    }
6394
6395    /// Fires `enter_every_rule` on registered parse listeners, returning the
6396    /// abort error if any listener requested one.
6397    ///
6398    /// Generated rule dispatch calls this after the depth-cap probe and
6399    /// before the rule body runs; the generated left-recursive loop calls it
6400    /// once per operator expansion, mirroring upstream ANTLR's simulated
6401    /// rule-entry event for `pushNewRecursionContext`. A listener abort is
6402    /// sticky exactly like a depth-cap violation: rule-level recovery absorbs
6403    /// the returned error, so the flag holds until the top-level entry drains
6404    /// it via [`Self::take_parse_listener_abort`] and fails the parse.
6405    pub fn parse_listener_enter_rule(&mut self, rule_index: usize) -> Option<AntlrError> {
6406        if self.parse_listeners.is_empty() {
6407            return None;
6408        }
6409        self.parse_listener_enter_rule_dispatch(rule_index)
6410    }
6411
6412    fn parse_listener_enter_rule_dispatch(&mut self, rule_index: usize) -> Option<AntlrError> {
6413        if let Some(error) = &self.parse_listener_abort {
6414            return Some(error.clone());
6415        }
6416        let event = EnterRuleEvent {
6417            rule_index,
6418            current: self.input.lt(1),
6419        };
6420        // Split borrows: the token view borrows the input while listeners
6421        // need `&mut`, so listeners are taken out for the dispatch. Listener
6422        // methods have no parser access and cannot observe the absence.
6423        let mut listeners = std::mem::take(&mut self.parse_listeners);
6424        let mut abort = None;
6425        for slot in &mut listeners {
6426            if let Err(error) = slot.0.enter_every_rule(&event) {
6427                abort = Some(error);
6428                break;
6429            }
6430        }
6431        self.parse_listeners = listeners;
6432        if let Some(error) = abort {
6433            self.parse_listener_abort = Some(error.clone());
6434            return Some(error);
6435        }
6436        None
6437    }
6438
6439    /// Fires `exit_every_rule` on registered parse listeners.
6440    ///
6441    /// Generated rule bodies call this on every exit path — success and
6442    /// recovery alike — keeping enter/exit pairs balanced, and the generated
6443    /// left-recursive loop calls it once per operator expansion when the rule
6444    /// finishes unrolling.
6445    pub fn parse_listener_exit_rule(&mut self, rule_index: usize) {
6446        if self.parse_listeners.is_empty() {
6447            return;
6448        }
6449        // Reverse registration order, matching upstream ANTLR
6450        // (`Parser.triggerExitRuleEvent` walks listeners back to front).
6451        for slot in self.parse_listeners.iter_mut().rev() {
6452            slot.0.exit_every_rule(rule_index);
6453        }
6454    }
6455
6456    /// Drains the sticky parse-listener abort recorded by
6457    /// [`Self::parse_listener_enter_rule`], if any.
6458    ///
6459    /// Generated top-level rule entries call this after recognition so an
6460    /// aborted parse fails even when recovery produced a tree, and so a
6461    /// reused parser starts its next parse clean.
6462    pub const fn take_parse_listener_abort(&mut self) -> Option<AntlrError> {
6463        self.parse_listener_abort.take()
6464    }
6465
6466    /// Drains every sticky parse abort — the depth-cap violation and the
6467    /// parse-listener abort — returning the depth error preferentially.
6468    ///
6469    /// Generated top-level rule entries call this on both exit paths: the
6470    /// recorded abort wins over errors derived from it (recovery may have
6471    /// absorbed the aborted rule and failed differently later), a recovered
6472    /// `Ok` tree still fails when an abort was recorded, and draining leaves
6473    /// the instance clean for the next entry-rule call.
6474    pub fn take_parse_abort(&mut self) -> Option<AntlrError> {
6475        if let Some(error) = self.rule_depth_error.take() {
6476            self.parse_listener_abort = None;
6477            return Some(error);
6478        }
6479        self.parse_listener_abort.take()
6480    }
6481
6482    /// Enters a generated parser rule and returns the context object the
6483    /// generated method should populate.
6484    pub fn enter_rule(&mut self, state: isize, rule_index: usize) -> ParserRuleContext {
6485        self.set_state(state);
6486        let invoking_state = self.pending_invoking_states.pop().unwrap_or(state);
6487        self.rule_context_stack.push(RuleContextFrame {
6488            rule_index,
6489            invoking_state,
6490        });
6491        self.advance_rule_context_version();
6492        let start_index = self.current_visible_index();
6493        let mut context = ParserRuleContext::new(rule_index, invoking_state);
6494        if let Some(token) = self.token_id_at(start_index) {
6495            self.set_context_start(&mut context, token);
6496        }
6497        context
6498    }
6499
6500    /// Records the ATN source state for the next generated rule invocation.
6501    ///
6502    /// ANTLR's full-context prediction reconstructs caller follow states from
6503    /// each active rule context's invoking state. Generated Rust rule methods are
6504    /// plain functions, so the caller supplies that ATN state just before making a
6505    /// rule call; `enter_rule` consumes it when the callee starts.
6506    pub fn push_invoking_state(&mut self, invoking_state: isize) -> usize {
6507        let marker = self.pending_invoking_states.len();
6508        self.pending_invoking_states.push(invoking_state);
6509        marker
6510    }
6511
6512    /// Discards an invoking-state marker if the callee did not consume it.
6513    pub fn discard_invoking_state(&mut self, marker: usize) {
6514        self.pending_invoking_states.truncate(marker);
6515    }
6516
6517    /// Exits the current generated parser rule.
6518    pub fn exit_rule(&mut self) {
6519        self.rule_context_stack.pop();
6520        self.advance_rule_context_version();
6521    }
6522
6523    /// Returns caller follow states for interning in a parser ATN simulator's
6524    /// prediction store. States are yielded outermost to innermost, with
6525    /// provable tail-call frames omitted because they would be popped before
6526    /// prediction can observe them.
6527    pub fn prediction_context_return_states<'a>(
6528        &'a self,
6529        atn: &'a Atn,
6530    ) -> impl DoubleEndedIterator<Item = usize> + 'a {
6531        self.rule_context_stack.iter().skip(1).filter_map(|frame| {
6532            let Ok(state_number) = usize::try_from(frame.invoking_state) else {
6533                return None;
6534            };
6535            let transition = atn
6536                .state(state_number)
6537                .and_then(|state| state.transitions().first())?;
6538            if transition.is_tail_call() {
6539                return None;
6540            }
6541            let Transition::Rule { follow_state, .. } = transition.data() else {
6542                return None;
6543            };
6544            Some(follow_state)
6545        })
6546    }
6547
6548    /// Returns a generation that changes whenever the active rule stack changes.
6549    ///
6550    /// A parser ATN simulator uses this to reuse an interned outer prediction
6551    /// context while generated predictions remain in the same rule context.
6552    pub const fn rule_context_version(&self) -> usize {
6553        self.rule_context_version
6554    }
6555
6556    const fn advance_rule_context_version(&mut self) {
6557        self.rule_context_version = self.rule_context_version.wrapping_add(1);
6558    }
6559
6560    /// Adds a generated parser child only when parse-tree construction is
6561    /// enabled. The match is recorded on the context either way (via `add_child`,
6562    /// or `note_matched_child` when trees are off) so generated recovery can tell
6563    /// whether the rule has matched anything yet without depending on `children`.
6564    pub fn add_parse_child(&mut self, context: &mut ParserRuleContext, child: ParseTree) {
6565        if self.build_parse_trees {
6566            self.tree.add_child(context, child);
6567        } else {
6568            context.note_matched_child();
6569        }
6570    }
6571
6572    /// Combined sync-decision + child-append + sync-error capture.
6573    ///
6574    /// Replaces the 9-line generated sync-decision motif with a single call.
6575    /// On success, appends any sync children to the context. On error, stores
6576    /// the error in `sync_error` and returns `Err` for the caller to propagate.
6577    #[inline]
6578    pub fn sync_into(
6579        &mut self,
6580        atn: &Atn,
6581        state_number: usize,
6582        context: &mut ParserRuleContext,
6583        loop_back: bool,
6584        sync_error: &mut Option<AntlrError>,
6585    ) -> Result<(), AntlrError> {
6586        let current_context_empty = !context.has_matched_child();
6587        match self.sync_decision(atn, state_number, current_context_empty, loop_back) {
6588            Ok(children) => {
6589                for child in children {
6590                    self.add_parse_child(context, child);
6591                }
6592                Ok(())
6593            }
6594            Err(error) => {
6595                *sync_error = Some(error.clone());
6596                Err(error)
6597            }
6598        }
6599    }
6600
6601    /// Combined token-match + EOF accounting + child append.
6602    ///
6603    /// Replaces the 3-line generated token-match motif with a single call.
6604    #[inline]
6605    pub fn match_token_into(
6606        &mut self,
6607        token_type: i32,
6608        follow_state: usize,
6609        atn: &Atn,
6610        context: &mut ParserRuleContext,
6611        consumed_eof: &mut bool,
6612    ) -> Result<(), AntlrError> {
6613        let m = self.match_token_recovering(token_type, follow_state, atn)?;
6614        *consumed_eof |= m.consumed_eof();
6615        for child in m.into_child_iter() {
6616            self.add_parse_child(context, child);
6617        }
6618        Ok(())
6619    }
6620
6621    /// Combined set-match + EOF accounting + child append (ATN token-set
6622    /// variant).
6623    #[inline]
6624    pub fn match_token_set_into(
6625        &mut self,
6626        token_set: ParserIntervalSet<'_>,
6627        follow_state: usize,
6628        atn: &Atn,
6629        context: &mut ParserRuleContext,
6630        consumed_eof: &mut bool,
6631    ) -> Result<(), AntlrError> {
6632        let m = self.match_token_set_recovering(token_set, follow_state, atn)?;
6633        *consumed_eof |= m.consumed_eof();
6634        for child in m.into_child_iter() {
6635            self.add_parse_child(context, child);
6636        }
6637        Ok(())
6638    }
6639
6640    /// Combined set-match + EOF accounting + child append (inline intervals
6641    /// variant).
6642    #[inline]
6643    pub fn match_set_into(
6644        &mut self,
6645        intervals: &[(i32, i32)],
6646        follow_state: usize,
6647        atn: &Atn,
6648        context: &mut ParserRuleContext,
6649        consumed_eof: &mut bool,
6650    ) -> Result<(), AntlrError> {
6651        let m = self.match_set_recovering(intervals, follow_state, atn)?;
6652        *consumed_eof |= m.consumed_eof();
6653        for child in m.into_child_iter() {
6654            self.add_parse_child(context, child);
6655        }
6656        Ok(())
6657    }
6658
6659    /// Combined not-set-match + EOF accounting + child append (ATN token-set
6660    /// complement variant).
6661    #[allow(clippy::too_many_arguments)]
6662    #[inline]
6663    pub fn match_not_token_set_into(
6664        &mut self,
6665        token_set: ParserIntervalSet<'_>,
6666        min_vocabulary: i32,
6667        max_vocabulary: i32,
6668        follow_state: usize,
6669        atn: &Atn,
6670        context: &mut ParserRuleContext,
6671        consumed_eof: &mut bool,
6672    ) -> Result<(), AntlrError> {
6673        let m = self.match_not_token_set_recovering(
6674            token_set,
6675            min_vocabulary,
6676            max_vocabulary,
6677            follow_state,
6678            atn,
6679        )?;
6680        *consumed_eof |= m.consumed_eof();
6681        for child in m.into_child_iter() {
6682            self.add_parse_child(context, child);
6683        }
6684        Ok(())
6685    }
6686
6687    /// Combined not-set-match + EOF accounting + child append (inline intervals
6688    /// complement variant).
6689    #[allow(clippy::too_many_arguments)]
6690    #[inline]
6691    pub fn match_not_set_into(
6692        &mut self,
6693        intervals: &[(i32, i32)],
6694        min_vocabulary: i32,
6695        max_vocabulary: i32,
6696        follow_state: usize,
6697        atn: &Atn,
6698        context: &mut ParserRuleContext,
6699        consumed_eof: &mut bool,
6700    ) -> Result<(), AntlrError> {
6701        let m = self.match_not_set_recovering(
6702            intervals,
6703            min_vocabulary,
6704            max_vocabulary,
6705            follow_state,
6706            atn,
6707        )?;
6708        *consumed_eof |= m.consumed_eof();
6709        for child in m.into_child_iter() {
6710            self.add_parse_child(context, child);
6711        }
6712        Ok(())
6713    }
6714
6715    fn release_tree_scratch_if_idle(&mut self) {
6716        if self.rule_context_stack.is_empty() {
6717            self.tree.release_scratch();
6718        }
6719    }
6720
6721    /// Finishes a generated parser rule and returns its parse-tree node.
6722    pub fn finish_rule(&mut self, mut context: ParserRuleContext, consumed_eof: bool) -> ParseTree {
6723        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6724        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6725            self.set_context_stop(&mut context, token);
6726        }
6727        let node = self.rule_node(context);
6728        self.exit_rule();
6729        self.release_tree_scratch_if_idle();
6730        node
6731    }
6732
6733    /// Recovers a generated rule catch block after a committed mismatch.
6734    ///
6735    /// ANTLR's generated parsers catch recognition errors inside each rule,
6736    /// report the original error, then consume unexpected tokens until the
6737    /// caller's recovery set can resume. Tokens consumed during recovery become
6738    /// error nodes in the current rule context.
6739    pub fn recover_generated_rule(
6740        &mut self,
6741        context: &mut ParserRuleContext,
6742        atn: &Atn,
6743        error: AntlrError,
6744    ) {
6745        let diagnostic = self.generated_rule_error_diagnostic(error);
6746        self.push_generated_parser_diagnostic(diagnostic);
6747        self.generated_sync_expected = None;
6748        let error_index = self.input.index();
6749        let error_state = self.data.state();
6750        // Match ANTLR's lastErrorIndex/lastErrorStates failsafe: a recovery
6751        // token can also be in the caller's follow set, leaving the cursor
6752        // unchanged and allowing generated outer decisions to revisit the same
6753        // failed state forever.
6754        if self.generated_recovery_error_index == Some(error_index)
6755            && self.generated_recovery_error_states.contains(&error_state)
6756            && self.la(1) != TOKEN_EOF
6757            && let Some(token) = self.input.lt_id(1)
6758        {
6759            self.consume();
6760            let child = self.error_tree(token);
6761            self.add_parse_child(context, child);
6762        }
6763        let recovery_index = self.input.index();
6764        if self.generated_recovery_error_index != Some(recovery_index) {
6765            self.generated_recovery_error_index = Some(recovery_index);
6766            self.generated_recovery_error_states.clear();
6767        }
6768        self.generated_recovery_error_states.insert(error_state);
6769        let recovery_symbols = self.context_expected_symbols(atn);
6770        loop {
6771            let symbol = self.la(1);
6772            if symbol == TOKEN_EOF || recovery_symbols.contains(&symbol) {
6773                break;
6774            }
6775            let Some(token) = self.input.lt_id(1) else {
6776                break;
6777            };
6778            self.consume();
6779            let child = self.error_tree(token);
6780            self.add_parse_child(context, child);
6781        }
6782        self.record_syntax_errors(1);
6783    }
6784
6785    fn reset_generated_recovery_state(&mut self) {
6786        if self.generated_recovery_error_index.is_some() {
6787            self.generated_recovery_error_index = None;
6788            self.generated_recovery_error_states.clear();
6789        }
6790    }
6791
6792    fn push_generated_parser_diagnostic(&mut self, diagnostic: ParserDiagnostic) {
6793        if self
6794            .generated_parser_diagnostics
6795            .iter()
6796            .any(|existing| existing == &diagnostic)
6797        {
6798            return;
6799        }
6800        self.generated_parser_diagnostics.push(diagnostic);
6801    }
6802
6803    fn generated_rule_error_diagnostic(&self, error: AntlrError) -> ParserDiagnostic {
6804        match error {
6805            // The anchor recorded where the error was built wins over the
6806            // current lookahead: prediction restores the cursor, so lt(1)
6807            // here can point at the decision start rather than the error.
6808            AntlrError::ParserError {
6809                line,
6810                column,
6811                message,
6812                offending,
6813            } => ParserDiagnostic {
6814                line,
6815                column,
6816                message,
6817                offending,
6818            },
6819            AntlrError::MismatchedInput { expected, found } => diagnostic_for_token(
6820                self.input.lt(1),
6821                format!("mismatched input {found} expecting {expected}"),
6822            ),
6823            AntlrError::NoViableAlternative { input } => diagnostic_for_token(
6824                self.input.lt(1),
6825                format!("no viable alternative at input {input}"),
6826            ),
6827            AntlrError::LexerError {
6828                line,
6829                column,
6830                message,
6831            } => ParserDiagnostic {
6832                line,
6833                column,
6834                message,
6835                offending: None,
6836            },
6837            AntlrError::Unsupported(message) => diagnostic_for_token(self.input.lt(1), message),
6838        }
6839    }
6840
6841    /// Finishes a generated left-recursive parser rule and returns its parse-tree node.
6842    pub fn finish_recursion_rule(
6843        &mut self,
6844        mut context: ParserRuleContext,
6845        consumed_eof: bool,
6846    ) -> ParseTree {
6847        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6848        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6849            self.set_context_stop(&mut context, token);
6850        }
6851        let node = self.rule_node(context);
6852        self.unroll_recursion_context();
6853        self.release_tree_scratch_if_idle();
6854        node
6855    }
6856
6857    /// Enters a generated left-recursive rule at `precedence`.
6858    pub fn enter_recursion_rule(
6859        &mut self,
6860        state: isize,
6861        rule_index: usize,
6862        precedence: i32,
6863    ) -> ParserRuleContext {
6864        self.precedence_stack.push(precedence);
6865        self.recursion_expansion_marks
6866            .push(self.recursion_expansions);
6867        self.enter_rule(state, rule_index)
6868    }
6869
6870    /// Replaces the current context while expanding a left-recursive rule.
6871    pub fn push_new_recursion_context(
6872        &mut self,
6873        state: isize,
6874        rule_index: usize,
6875    ) -> ParserRuleContext {
6876        self.set_state(state);
6877        // Counts toward the depth cap: upstream treats this as rule entry
6878        // (`Parser.pushNewRecursionContext` fires `triggerEnterRuleEvent`).
6879        self.recursion_expansions += 1;
6880        ParserRuleContext::new(rule_index, state)
6881    }
6882
6883    /// Wraps the previous left-recursive context before parsing the next
6884    /// recursive operator alternative.
6885    pub fn push_new_recursion_context_with_previous(
6886        &mut self,
6887        state: isize,
6888        rule_index: usize,
6889        current: &mut ParserRuleContext,
6890    ) {
6891        self.set_state(state);
6892        // Counts toward the depth cap: each operator iteration deepens the
6893        // parse tree one level without pushing a rule frame, and upstream
6894        // fires a rule-entry listener event for it. The parse-listener enter
6895        // event for this expansion fires from the generated loop's probe
6896        // just before this call, where a listener abort can propagate.
6897        self.recursion_expansions += 1;
6898        if let Some(stop) = self
6899            .rule_stop_token_index(self.input.index(), false)
6900            .and_then(|index| self.token_id_at(index))
6901        {
6902            self.set_context_stop(current, stop);
6903        }
6904        let invoking_state = current.invoking_state();
6905        let start = current.start_id();
6906        let mut replacement = ParserRuleContext::new(rule_index, invoking_state);
6907        if start.is_some() {
6908            replacement.set_start_from_context(current);
6909        }
6910        let previous = std::mem::replace(current, replacement);
6911        if self.build_parse_trees {
6912            let previous = self.rule_node(previous);
6913            self.tree.add_child(current, previous);
6914        }
6915    }
6916
6917    /// Leaves a generated left-recursive rule.
6918    pub fn unroll_recursion_context(&mut self) {
6919        if self.precedence_stack.len() > 1 {
6920            self.precedence_stack.pop();
6921        }
6922        // Parse-listener exits for expansions fire inside the generated
6923        // operator loop (top of each pass, upstream's `recRuleSetPrevCtx`),
6924        // and the dispatch wrapper's exit covers the final live context —
6925        // upstream's `unrollRecursionContexts` walks exactly one link, so no
6926        // batched exits happen here. Only the depth-cap accounting rewinds.
6927        if let Some(mark) = self.recursion_expansion_marks.pop() {
6928            self.recursion_expansions = mark;
6929        }
6930        self.exit_rule();
6931    }
6932
6933    /// Predicts a generated left-recursive loop from one-token lookahead.
6934    ///
6935    /// `Some(true)` enters the operator alternative, `Some(false)` exits, and
6936    /// `None` means caller overlap, a dangerous multi-token prefix, or an
6937    /// unresolved semantic predicate requires full `StarLoopEntry` adaptive
6938    /// prediction (which includes the exit alt and precedence filtering).
6939    ///
6940    /// Single-token operators and multi-token prefixes that do not shadow a
6941    /// lower-precedence single-token operator keep the one-token enter fast path.
6942    ///
6943    /// Multi-token prefixes that **do** shadow a lower-precedence single-token
6944    /// operator must not force enter; the adaptive decision may need to select
6945    /// the loop exit instead.
6946    pub fn left_recursive_loop_enter_prediction(
6947        &mut self,
6948        atn: &Atn,
6949        state_number: usize,
6950        precedence: i32,
6951    ) -> Option<bool> {
6952        let symbol = self.la(1);
6953        if symbol == TOKEN_EOF {
6954            return Some(false);
6955        }
6956        let operator_lookahead =
6957            Self::cached_left_recursive_operator_lookahead(atn, state_number, precedence);
6958        let can_single = operator_lookahead.single_token.contains(symbol);
6959        let can_multi = operator_lookahead.multi_token_prefix.contains(symbol);
6960        let can_predicate = operator_lookahead.predicate_dependent.contains(symbol);
6961        if !can_single && !can_multi && !can_predicate {
6962            return Some(false);
6963        }
6964        if can_predicate && !can_single {
6965            return None;
6966        }
6967        // Multi-token-only at this precedence, but the same symbol is a
6968        // single-token operator at precedence 0: defer so exit can win when the
6969        // multi-token sequence does not actually match (e.g. `>` vs `>>`).
6970        if !can_single && can_multi && precedence > 0 {
6971            let baseline = Self::cached_left_recursive_operator_lookahead(atn, state_number, 0);
6972            if baseline.single_token.contains(symbol) {
6973                return None;
6974            }
6975        }
6976        let atn_key = SharedAtnCacheKey::for_atn(atn);
6977        let cached_overlap = self
6978            .left_recursive_caller_overlap_cache
6979            .iter()
6980            .flatten()
6981            .find(|entry| {
6982                entry.atn_key == atn_key
6983                    && entry.state_number == state_number
6984                    && entry.symbol == symbol
6985                    && entry.context_version == self.rule_context_version
6986            })
6987            .map(|entry| entry.overlaps);
6988        let caller_overlaps = cached_overlap.unwrap_or_else(|| {
6989            let overlaps = caller_context_can_match_symbol_before_state(
6990                atn,
6991                self.prediction_context_return_states(atn),
6992                state_number,
6993                symbol,
6994            );
6995            if let Some(slot) = self
6996                .left_recursive_caller_overlap_cache
6997                .iter_mut()
6998                .find(|slot| slot.is_none())
6999            {
7000                *slot = Some(LeftRecursiveCallerOverlap {
7001                    atn_key,
7002                    state_number,
7003                    symbol,
7004                    context_version: self.rule_context_version,
7005                    overlaps,
7006                });
7007            }
7008            overlaps
7009        });
7010        if caller_overlaps {
7011            return None;
7012        }
7013        Some(true)
7014    }
7015
7016    fn cached_left_recursive_operator_lookahead(
7017        atn: &Atn,
7018        state_number: usize,
7019        precedence: i32,
7020    ) -> Rc<LeftRecursiveOperatorLookahead> {
7021        with_shared_atn_caches(atn, |cache| {
7022            let key = (state_number, precedence);
7023            if let Some(cached) = cache.left_recursive_operator_lookahead.get(&key) {
7024                return Rc::clone(cached);
7025            }
7026            let lookahead = Rc::new(left_recursive_operator_lookahead(
7027                atn,
7028                state_number,
7029                precedence,
7030            ));
7031            cache
7032                .left_recursive_operator_lookahead
7033                .insert(key, Rc::clone(&lookahead));
7034            lookahead
7035        })
7036    }
7037
7038    /// Checks whether a generated left-recursive loop can unambiguously enter
7039    /// its operator alternative from one-token lookahead.
7040    pub fn left_recursive_loop_enter_matches(
7041        &mut self,
7042        atn: &Atn,
7043        state_number: usize,
7044        precedence: i32,
7045    ) -> bool {
7046        self.left_recursive_loop_enter_prediction(atn, state_number, precedence) == Some(true)
7047    }
7048
7049    /// Implements generated `precpred(_ctx, k)` checks.
7050    pub fn precpred(&self, precedence: i32) -> bool {
7051        precedence >= self.precedence_stack.last().copied().unwrap_or_default()
7052    }
7053
7054    /// Evaluates a generated parser semantic predicate at the current input
7055    /// position.
7056    pub fn parser_semantic_predicate_matches(
7057        &mut self,
7058        predicates: &[(usize, usize, ParserPredicate)],
7059        rule_index: usize,
7060        pred_index: usize,
7061    ) -> bool {
7062        self.parser_semantic_predicate_matches_inner(predicates, rule_index, pred_index, None)
7063    }
7064
7065    /// Evaluates a generated parser semantic predicate with the current integer
7066    /// rule argument exposed as `$_p`/`$i` metadata where applicable.
7067    pub fn parser_semantic_predicate_matches_with_local(
7068        &mut self,
7069        predicates: &[(usize, usize, ParserPredicate)],
7070        rule_index: usize,
7071        pred_index: usize,
7072        local_int_arg: i32,
7073    ) -> bool {
7074        self.parser_semantic_predicate_matches_inner(
7075            predicates,
7076            rule_index,
7077            pred_index,
7078            Some((rule_index, i64::from(local_int_arg))),
7079        )
7080    }
7081
7082    fn parser_semantic_predicate_matches_inner(
7083        &mut self,
7084        predicates: &[(usize, usize, ParserPredicate)],
7085        rule_index: usize,
7086        pred_index: usize,
7087        local_int_arg: Option<(usize, i64)>,
7088    ) -> bool {
7089        let index = self.input.index();
7090        let member_values = self.int_members.clone();
7091        self.parser_predicate_matches(PredicateEval {
7092            index,
7093            rule_index,
7094            pred_index,
7095            predicates,
7096            semantics: None,
7097            context: None,
7098            local_int_arg,
7099            member_values: &member_values,
7100        })
7101    }
7102
7103    /// Evaluates a generated parser semantic predicate with access to the
7104    /// current generated rule context.
7105    pub fn parser_semantic_predicate_matches_with_context_and_local(
7106        &mut self,
7107        predicates: &[(usize, usize, ParserPredicate)],
7108        rule_index: usize,
7109        pred_index: usize,
7110        context: &ParserRuleContext,
7111        local_int_arg: i32,
7112    ) -> bool {
7113        let index = self.input.index();
7114        let member_values = self.int_members.clone();
7115        self.parser_predicate_matches(PredicateEval {
7116            index,
7117            rule_index,
7118            pred_index,
7119            predicates,
7120            semantics: None,
7121            context: Some(context),
7122            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
7123            member_values: &member_values,
7124        })
7125    }
7126
7127    /// Evaluates a generated `SemIR` parser predicate with access to the current
7128    /// generated rule context.
7129    pub fn parser_semantic_ir_predicate_matches_with_context_and_local(
7130        &mut self,
7131        semantics: &ParserSemantics,
7132        rule_index: usize,
7133        pred_index: usize,
7134        context: &ParserRuleContext,
7135        local_int_arg: i32,
7136    ) -> bool {
7137        let index = self.input.index();
7138        let member_values = self.int_members.clone();
7139        self.parser_predicate_matches(PredicateEval {
7140            index,
7141            rule_index,
7142            pred_index,
7143            predicates: &[],
7144            semantics: Some(semantics),
7145            context: Some(context),
7146            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
7147            member_values: &member_values,
7148        })
7149    }
7150
7151    /// Returns a generated fail-option message for a parser semantic
7152    /// predicate coordinate.
7153    pub fn parser_semantic_predicate_failure_message(
7154        &self,
7155        rule_index: usize,
7156        pred_index: usize,
7157        predicates: &[(usize, usize, ParserPredicate)],
7158    ) -> Option<&'static str> {
7159        self.parser_predicate_failure_message(rule_index, pred_index, predicates)
7160    }
7161
7162    /// Matches any non-EOF token.
7163    pub fn match_wildcard(&mut self) -> Result<ParseTree, AntlrError> {
7164        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
7165            line: 0,
7166            column: 0,
7167            message: "missing current token".to_owned(),
7168            offending: None,
7169        })?;
7170        if self.token_type_for_id(current) == TOKEN_EOF {
7171            return Err(AntlrError::MismatchedInput {
7172                expected: "wildcard".to_owned(),
7173                found: self.vocabulary().display_name(TOKEN_EOF),
7174            });
7175        }
7176        self.reset_generated_recovery_state();
7177        self.consume();
7178        Ok(self.terminal_tree(current))
7179    }
7180
7181    /// Generated parser synchronization hook. The current interpreter owns
7182    /// recovery; direct generated methods can call this as a no-op until the
7183    /// generated recovery strategy is expanded.
7184    #[allow(clippy::unnecessary_wraps)]
7185    pub fn sync(&mut self, state: isize) -> Result<(), AntlrError> {
7186        self.set_state(state);
7187        Ok(())
7188    }
7189
7190    /// Synchronizes a generated parser decision against the ATN lookahead set.
7191    ///
7192    /// ANTLR generated parsers call the error strategy before optional and loop
7193    /// decisions. When the current token cannot start any alternative, follow a
7194    /// nullable exit, or be deleted before a later synchronization token, the
7195    /// generated Rust method reports that decision-level mismatch instead of
7196    /// descending into a child rule that cannot start at the current token.
7197    pub fn sync_decision(
7198        &mut self,
7199        atn: &Atn,
7200        state_number: usize,
7201        _current_context_empty: bool,
7202        loop_back: bool,
7203    ) -> Result<Vec<ParseTree>, AntlrError> {
7204        self.set_state(isize::try_from(state_number).unwrap_or(isize::MAX));
7205        self.generated_sync_expected = None;
7206        let Some(state) = atn.state(state_number) else {
7207            return Ok(Vec::new());
7208        };
7209        let Some(rule_index) = state.rule_index() else {
7210            return Ok(Vec::new());
7211        };
7212        let Some(rule_stop) = atn.rule_to_stop_state().get(rule_index) else {
7213            return Ok(Vec::new());
7214        };
7215        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7216        let symbol = self.la(1);
7217        let mut has_expected_symbols = false;
7218        let mut nullable = false;
7219        // Whether EOF is an EXPLICIT expected token of this decision (a real `EOF`
7220        // reference in the grammar, e.g. `A* EOF`), as opposed to merely the
7221        // implicit rule-follow that a nullable exit inherits (e.g. a start rule's
7222        // end). Only an explicit EOF makes a token-before-EOF genuinely extraneous
7223        // and worth deleting; an implicit-follow EOF means the loop should simply
7224        // exit and leave the token for the (absent) caller — matching ANTLR, which
7225        // exits the loop via prediction rather than consuming up to a synthetic EOF.
7226        let mut explicit_eof_expected = false;
7227        for transition in &entry.transitions {
7228            if transition.symbols.contains(symbol) {
7229                return Ok(Vec::new());
7230            }
7231            has_expected_symbols |= !transition.symbols.is_empty();
7232            nullable |= transition.nullable;
7233            explicit_eof_expected |= transition.symbols.contains(TOKEN_EOF);
7234        }
7235        // Java's DefaultErrorStrategy.sync returns as soon as nextTokens
7236        // contains EPSILON. It remembers the decision/context expected set for
7237        // a later mismatch, but must not attempt single-token deletion or
7238        // loop-back recovery first: a nullable decision leaves the current
7239        // token to its caller even when that token is not in the context-free
7240        // FOLLOW set.
7241        if nullable {
7242            // Valid exits only need a membership probe. Materialize the full
7243            // expected set below solely when a later caller mismatch may need
7244            // the combined decision/context diagnostic.
7245            if self.context_expected_contains(atn, symbol) {
7246                return Ok(Vec::new());
7247            }
7248            let mut expected = self.context_expected_token_set(atn);
7249            for transition in &entry.transitions {
7250                expected.extend_from(&transition.symbols);
7251            }
7252            self.generated_sync_expected = Some(expected);
7253            return Ok(Vec::new());
7254        }
7255        if !has_expected_symbols {
7256            return Ok(Vec::new());
7257        }
7258        let mut expected = TokenBitSet::default();
7259        for transition in &entry.transitions {
7260            expected.extend_from(&transition.symbols);
7261        }
7262        // ANTLR's `DefaultErrorStrategy.sync` recovers differently by decision kind:
7263        // a loop-BACK sync (STAR_LOOP_BACK / PLUS_LOOP_BACK — reached only after at
7264        // least one iteration) does `consumeUntil` the follow set — multi-token
7265        // deletion, one error per skipped token across iterations; a loop ENTRY
7266        // (STAR_LOOP_ENTRY) and a plain optional/block entry (BLOCK_START /
7267        // *-block / +-block starts) do `singleTokenDeletion` — delete the one
7268        // unexpected token only when LA(2) is expected, otherwise report a mismatch
7269        // and leave recovery to the rule.
7270        //
7271        // The generated loop always presents the loop-ENTRY state to this method on
7272        // every pass, so `state.kind()` cannot distinguish entry from back; the caller
7273        // passes `loop_back` (false on a `*` loop's first sync / on a block, true once
7274        // an iteration has been taken, and true on a `+` loop's first sync since its
7275        // mandatory first element is iteration 1). Treating a loop entry as a
7276        // loop-back would over-consume (e.g. `s: A* EOF;` on `c c` would delete both
7277        // `c`s, which ANTLR rejects with `mismatched input`).
7278        let loop_sync = loop_back;
7279        if symbol != TOKEN_EOF {
7280            let mut cursor = self.input.index();
7281            let mut skipped = Vec::new();
7282            loop {
7283                let current = self.token_type_at(cursor);
7284                if current == TOKEN_EOF {
7285                    break;
7286                }
7287                skipped.push(cursor);
7288                let next = self.consume_index(cursor, current);
7289                if next == cursor {
7290                    break;
7291                }
7292                let next_symbol = self.token_type_at(next);
7293                // Stop (and delete the skipped tokens as error nodes) when the next
7294                // token is a real expected continuation. EOF counts only when it is
7295                // an EXPLICIT grammar token (`A* EOF`): then the deleted tokens are
7296                // genuinely extraneous and the generated EOF match consumes the real
7297                // EOF afterwards. An implicit-follow EOF (a nullable exit's inherited
7298                // rule-follow) does NOT count — the loop must exit and leave the
7299                // token, as ANTLR does, instead of deleting up to a synthetic EOF.
7300                let next_is_expected_stop = if next_symbol == TOKEN_EOF {
7301                    explicit_eof_expected
7302                } else {
7303                    expected.contains(next_symbol)
7304                };
7305                if next_is_expected_stop {
7306                    let current_token = self.input.lt(1);
7307                    let expected_symbols = expected.to_btree_set();
7308                    let message = format!(
7309                        "extraneous input {} expecting {}",
7310                        current_token
7311                            .as_ref()
7312                            .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7313                        self.expected_symbols_display(&expected_symbols)
7314                    );
7315                    self.push_generated_parser_diagnostic(diagnostic_for_token(
7316                        current_token,
7317                        message,
7318                    ));
7319                    self.record_syntax_errors(1);
7320                    let mut children = Vec::with_capacity(skipped.len());
7321                    for index in skipped {
7322                        if let Some(token) = self.token_id_at(index) {
7323                            self.consume();
7324                            children.push(self.error_tree(token));
7325                        }
7326                    }
7327                    if !loop_sync {
7328                        self.reset_generated_recovery_state();
7329                    }
7330                    return Ok(children);
7331                }
7332                // A non-loop block entry deletes at most one token (single-token
7333                // deletion): if LA(2) is not expected, stop scanning so the mismatch
7334                // is reported at the first token instead of skipping ahead.
7335                if !loop_sync {
7336                    break;
7337                }
7338                cursor = next;
7339            }
7340        }
7341        let current = self.input.lt(1);
7342        let expected_symbols = expected.to_btree_set();
7343        Err(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!(
7347                "mismatched input {} expecting {}",
7348                current
7349                    .as_ref()
7350                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7351                self.expected_symbols_display(&expected_symbols)
7352            ),
7353            offending: current.as_ref().map(Token::token_id),
7354        })
7355    }
7356
7357    /// Returns a generated-parser prediction when one token of lookahead
7358    /// uniquely selects an alternative for `state_number`.
7359    ///
7360    /// This mirrors the interpreter's LL(1) commit point and lets generated
7361    /// recursive-descent methods avoid invoking the adaptive simulator for
7362    /// simple optional/block/loop decisions.
7363    pub fn ll1_decision_prediction(
7364        &mut self,
7365        atn: &Atn,
7366        state_number: usize,
7367    ) -> Option<ParserAtnPrediction> {
7368        let state = atn.state(state_number)?;
7369        if state.precedence_rule_decision() {
7370            return None;
7371        }
7372        let rule_stop = state
7373            .rule_index()
7374            .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))?;
7375        let symbol = self.la(1);
7376        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7377        ll1_greedy_alt(&entry, symbol, state.non_greedy()).map(|alt| ParserAtnPrediction {
7378            alt: alt + 1,
7379            requires_full_context: false,
7380            has_semantic_context: false,
7381            diagnostic: None,
7382        })
7383    }
7384
7385    fn context_expected_symbols(&mut self, atn: &Atn) -> BTreeSet<i32> {
7386        let mut expected = BTreeSet::new();
7387        for index in (1..self.rule_context_stack.len()).rev() {
7388            let invoking_state = self.rule_context_stack[index].invoking_state;
7389            let Ok(state_number) = usize::try_from(invoking_state) else {
7390                continue;
7391            };
7392            let Some(Transition::Rule { follow_state, .. }) = atn
7393                .state(state_number)
7394                .and_then(|state| state.transitions().first())
7395                .map(ParserTransition::data)
7396            else {
7397                continue;
7398            };
7399            let return_state = follow_state;
7400            expected.extend(self.cached_state_expected_symbols(atn, return_state).iter());
7401            if !self.cached_state_can_reach_rule_stop(atn, return_state) {
7402                return expected;
7403            }
7404        }
7405        expected.insert(TOKEN_EOF);
7406        expected
7407    }
7408
7409    fn context_expected_token_set(&mut self, atn: &Atn) -> TokenBitSet {
7410        let mut expected = TokenBitSet::default();
7411        for index in (1..self.rule_context_stack.len()).rev() {
7412            let invoking_state = self.rule_context_stack[index].invoking_state;
7413            let Ok(state_number) = usize::try_from(invoking_state) else {
7414                continue;
7415            };
7416            let Some(Transition::Rule { follow_state, .. }) = atn
7417                .state(state_number)
7418                .and_then(|state| state.transitions().first())
7419                .map(ParserTransition::data)
7420            else {
7421                continue;
7422            };
7423            expected.extend_from(&self.cached_state_expected_token_set(atn, follow_state));
7424            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7425                return expected;
7426            }
7427        }
7428        expected.insert(TOKEN_EOF);
7429        expected
7430    }
7431
7432    /// Reports whether `symbol` is in `context_expected_token_set(atn)`
7433    /// without materializing the union.
7434    ///
7435    /// The walk follows the same rule-stack return chain as adaptive
7436    /// prediction. Valid nullable exits normally match the innermost frame,
7437    /// keeping their synchronization path to one cached membership probe.
7438    fn context_expected_contains(&mut self, atn: &Atn, symbol: i32) -> bool {
7439        for index in (1..self.rule_context_stack.len()).rev() {
7440            let invoking_state = self.rule_context_stack[index].invoking_state;
7441            let Ok(state_number) = usize::try_from(invoking_state) else {
7442                continue;
7443            };
7444            let Some(Transition::Rule { follow_state, .. }) = atn
7445                .state(state_number)
7446                .and_then(|state| state.transitions().first())
7447                .map(ParserTransition::data)
7448            else {
7449                continue;
7450            };
7451            if self
7452                .cached_state_expected_token_set(atn, follow_state)
7453                .contains(symbol)
7454            {
7455                return true;
7456            }
7457            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7458                return false;
7459            }
7460        }
7461        symbol == TOKEN_EOF
7462    }
7463
7464    /// Builds a generated no-viable-alternative parser error.
7465    pub fn no_viable_alternative_error(&self, start_index: usize) -> AntlrError {
7466        let error_index = self.input.index();
7467        self.no_viable_alternative_error_at(start_index, error_index)
7468    }
7469
7470    /// Builds a generated no-viable-alternative parser error at the simulator's
7471    /// failing lookahead index. `adaptive_predict` restores the input cursor
7472    /// before returning, so generated parsers have to pass the recorded index
7473    /// explicitly to preserve ANTLR's LL(k) diagnostic span.
7474    pub fn no_viable_alternative_error_at(
7475        &self,
7476        start_index: usize,
7477        error_index: usize,
7478    ) -> AntlrError {
7479        let diagnostic = self.no_viable_alternative(start_index, error_index);
7480        AntlrError::ParserError {
7481            line: diagnostic.line,
7482            column: diagnostic.column,
7483            message: diagnostic.message,
7484            offending: diagnostic.offending,
7485        }
7486    }
7487
7488    /// Builds a generated failed-predicate parser error.
7489    pub fn failed_predicate_error(&self, message: impl Into<String>) -> AntlrError {
7490        let current = self.input.lt(1);
7491        AntlrError::ParserError {
7492            line: current.as_ref().map(Token::line).unwrap_or_default(),
7493            column: current.as_ref().map(Token::column).unwrap_or_default(),
7494            message: format!("rule failed predicate: {}", message.into()),
7495            offending: current.as_ref().map(Token::token_id),
7496        }
7497    }
7498
7499    /// Builds a generated parser error for a semantic predicate with ANTLR's
7500    /// `<fail='...'>` option.
7501    pub fn failed_predicate_option_error(
7502        &self,
7503        rule_index: usize,
7504        message: impl Into<String>,
7505    ) -> AntlrError {
7506        let current = self.input.lt(1);
7507        let rule_name = self
7508            .rule_names()
7509            .get(rule_index)
7510            .map_or_else(|| rule_index.to_string(), Clone::clone);
7511        AntlrError::ParserError {
7512            line: current.as_ref().map(Token::line).unwrap_or_default(),
7513            column: current.as_ref().map(Token::column).unwrap_or_default(),
7514            message: format!("rule {rule_name} {}", message.into()),
7515            offending: current.as_ref().map(Token::token_id),
7516        }
7517    }
7518
7519    /// Builds a generated parser-action event at the current input position.
7520    pub fn parser_action_at_current(
7521        &mut self,
7522        source_state: usize,
7523        rule_index: usize,
7524        start_index: usize,
7525        consumed_eof: bool,
7526    ) -> ParserAction {
7527        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7528        ParserAction::new(source_state, rule_index, start_index, stop_index)
7529    }
7530
7531    /// Builds an indexed generated parser-action event at the current input position.
7532    pub fn parser_action_at_current_indexed(
7533        &mut self,
7534        source_state: usize,
7535        rule_index: usize,
7536        action_index: usize,
7537        start_index: usize,
7538        consumed_eof: bool,
7539    ) -> ParserAction {
7540        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7541        ParserAction::new_indexed(
7542            source_state,
7543            rule_index,
7544            action_index,
7545            start_index,
7546            stop_index,
7547        )
7548    }
7549
7550    /// Offers a committed parser action event to the user semantic hook.
7551    ///
7552    /// Generated parsers call this for action source states that were present
7553    /// in the ATN but not translated into a built-in Rust action template.
7554    pub fn parser_action_hook(&mut self, action: ParserAction, tree: ParseTree) -> bool {
7555        self.parser_action_hook_inner(action, None, Some(tree), None, true)
7556    }
7557
7558    /// Offers an action to semantic hooks at its committed grammar position.
7559    ///
7560    /// The current rule context contains children completed before the action;
7561    /// the full rule tree is not available until the rule returns.
7562    pub fn parser_action_hook_with_context(
7563        &mut self,
7564        action: ParserAction,
7565        context: &ParserRuleContext,
7566    ) -> bool {
7567        self.parser_action_hook_inner(action, Some(context), None, None, true)
7568    }
7569
7570    /// Offers an action with the current generated rule's integer argument.
7571    ///
7572    /// Generated parameterized rules use the same integer carrier as generated
7573    /// predicate evaluation. The context exposes it through
7574    /// [`ParserSemCtx::local_int_arg`].
7575    pub fn parser_action_hook_with_context_and_local(
7576        &mut self,
7577        action: ParserAction,
7578        context: &ParserRuleContext,
7579        local_int_arg: i32,
7580    ) -> bool {
7581        self.parser_action_hook_inner(
7582            action,
7583            Some(context),
7584            None,
7585            Some((action.rule_index(), i64::from(local_int_arg))),
7586            true,
7587        )
7588    }
7589
7590    /// Offers a rule-init action at rule entry while preserving legacy replay.
7591    ///
7592    /// A declined init is returned to the generated caller, so it is not an
7593    /// unhandled action yet and must not trip the fail-loud policy here.
7594    fn parser_rule_init_hook_with_context(
7595        &mut self,
7596        action: ParserAction,
7597        context: &ParserRuleContext,
7598        local_int_arg: Option<(usize, i64)>,
7599    ) -> bool {
7600        debug_assert!(action.is_rule_init());
7601        self.parser_action_hook_inner(action, Some(context), None, local_int_arg, false)
7602    }
7603
7604    fn parser_action_hook_inner(
7605        &mut self,
7606        action: ParserAction,
7607        context: Option<&ParserRuleContext>,
7608        tree: Option<ParseTree>,
7609        local_int_arg: Option<(usize, i64)>,
7610        record_unhandled: bool,
7611    ) -> bool {
7612        let rule_index = action.rule_index();
7613        let rule_name = self.rule_names().get(rule_index).cloned();
7614        let input = &mut self.input;
7615        let semantic_hooks = &mut self.semantic_hooks;
7616        let member_values = &self.int_members;
7617        let mut ctx = ParserSemCtx {
7618            input,
7619            tree_storage: &self.tree,
7620            rule_index,
7621            coordinate_index: action.action_index().unwrap_or(usize::MAX),
7622            rule_name,
7623            context,
7624            tree,
7625            local_int_arg,
7626            member_values,
7627            action: Some(action),
7628        };
7629        let handled = semantic_hooks.action(&mut ctx, action);
7630        // This action reached the hook because it had no translated arm. If no
7631        // hook handled it either (`SemanticHooks::action` returns `false`), the
7632        // committed action is silently dropped — record it so the parse entry
7633        // can fail loud under the fail-loud boundary, mirroring unknown
7634        // predicates. `assume-*` policies opt out of the fail-loud recording.
7635        if record_unhandled
7636            && !handled
7637            && matches!(self.unknown_predicate_policy, UnknownSemanticPolicy::Error)
7638        {
7639            let coordinate = (rule_index, action.source_state());
7640            if !self.unhandled_action_hits.contains(&coordinate) {
7641                self.unhandled_action_hits.push(coordinate);
7642            }
7643        }
7644        handled
7645    }
7646
7647    /// Attempts to execute a whole generated rule by committing simulator
7648    /// decisions directly. Unsupported constructs or decisions that need
7649    /// full-context / predicate evaluation restore the input cursor and fall
7650    /// back to [`Self::parse_atn_rule`].
7651    pub fn parse_atn_rule_adaptive_or_fallback<'atn>(
7652        &mut self,
7653        atn: &'atn Atn,
7654        simulator: &mut ParserAtnSimulator<'atn>,
7655        rule_index: usize,
7656    ) -> Result<ParseTree, AntlrError> {
7657        let start_index = self.current_visible_index();
7658        self.clear_prediction_diagnostics();
7659        self.reset_per_parse_caches();
7660        self.reset_recognition_arena();
7661        let tree_checkpoint = self.tree.checkpoint();
7662        let mut decision_by_state = vec![None; atn.states().len()];
7663        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
7664            if let Some(slot) = decision_by_state.get_mut(state_number) {
7665                *slot = Some(decision);
7666            }
7667        }
7668
7669        let result = DirectAdaptiveParser {
7670            parser: self,
7671            atn,
7672            simulator,
7673            decision_by_state,
7674            steps: 0,
7675        }
7676        .parse_rule(rule_index, -1, 0);
7677
7678        match result {
7679            Ok(tree) => {
7680                self.report_token_source_errors();
7681                self.release_tree_scratch_if_idle();
7682                Ok(tree)
7683            }
7684            Err(DirectAdaptiveParseControl::Fallback(reason)) => {
7685                let _ = reason;
7686                self.tree.rollback(tree_checkpoint);
7687                self.input.seek(start_index);
7688                self.parse_atn_rule(atn, rule_index)
7689            }
7690        }
7691    }
7692
7693    /// Parses a generated rule by interpreting the parser ATN from the rule's
7694    /// start state to its stop state.
7695    ///
7696    /// The recognizer backtracks across alternatives and loop exits using token
7697    /// stream indices instead of committing to input consumption immediately.
7698    /// Once a viable ATN path is found, the parser commits the accepted token
7699    /// interval and returns a rule node whose children mirror every grammar
7700    /// rule invocation reached on that path, matching ANTLR's parse-tree
7701    /// shape.
7702    pub fn parse_atn_rule(
7703        &mut self,
7704        atn: &Atn,
7705        rule_index: usize,
7706    ) -> Result<ParseTree, AntlrError> {
7707        self.parse_atn_rule_with_precedence(atn, rule_index, 0)
7708    }
7709
7710    /// Parses a generated rule by interpreting the parser ATN with an initial
7711    /// left-recursive precedence threshold.
7712    pub fn parse_atn_rule_with_precedence(
7713        &mut self,
7714        atn: &Atn,
7715        rule_index: usize,
7716        precedence: i32,
7717    ) -> Result<ParseTree, AntlrError> {
7718        self.parse_atn_rule_with_precedence_inner(
7719            atn,
7720            rule_index,
7721            precedence,
7722            None,
7723            AltNumberTracking::default(),
7724        )
7725    }
7726
7727    fn parse_atn_rule_with_precedence_inner(
7728        &mut self,
7729        atn: &Atn,
7730        rule_index: usize,
7731        precedence: i32,
7732        predicate_context: Option<FastPredicateContext<'_>>,
7733        alt_tracking: AltNumberTracking,
7734    ) -> Result<ParseTree, AntlrError> {
7735        let report_unrecovered_error = self.is_top_level_entry();
7736        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
7737            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
7738        })?;
7739        let stop_state = atn
7740            .rule_to_stop_state()
7741            .get(rule_index)
7742            .filter(|state| *state != usize::MAX)
7743            .ok_or_else(|| {
7744                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
7745            })?;
7746
7747        let start_index = self.current_visible_index();
7748        self.clear_prediction_diagnostics();
7749        self.reset_per_parse_caches();
7750        self.reset_recognition_arena();
7751        let caller_follow_state = self.pending_invoking_follow_state(atn);
7752        self.fast_recovery_enabled = false;
7753        self.fast_token_nodes_enabled = false;
7754        self.fast_track_alt_numbers = alt_tracking.any();
7755        let top_request = FastRecognizeTopRequest {
7756            start_state,
7757            stop_state,
7758            start_index,
7759            precedence,
7760            caller_follow_state,
7761        };
7762        let first_pass = self.fast_recognize_top(atn, top_request, predicate_context);
7763        self.fast_token_nodes_enabled = self.build_parse_trees;
7764        let needs_tree_retry = matches!(
7765            &first_pass,
7766            Ok((outcome, _, _))
7767                if self.build_parse_trees
7768                    && self
7769                        .recognition_arena
7770                        .sequence_has_left_recursive_boundary(outcome.nodes)
7771        );
7772        let needs_retry = match &first_pass {
7773            // The FIRST-set prefilter trims speculative rule calls that can't
7774            // match the current lookahead — useful for perf on grammars with
7775            // many epsilon-reachable rules, but the trim also bypasses
7776            // single-token insertion / deletion recovery that ANTLR's
7777            // reference parser runs at the child rule's first consuming
7778            // transition. Retry without the prefilter whenever the first pass
7779            // either produced no outcome at all or produced a recovered
7780            // outcome (diagnostics non-empty), since the second pass might
7781            // surface a child-level recovery with cleaner diagnostics or
7782            // closer parity to ANTLR's tree shape. Left-recursive tree
7783            // boundaries also need the token-node pass; otherwise the fold has
7784            // no concrete left operand to wrap into ANTLR's recursive context.
7785            Err(_) => true,
7786            Ok((outcome, _, _)) => !outcome.diagnostics.is_empty() || needs_tree_retry,
7787        };
7788        let (outcome, _expected, alt_number) = if needs_retry {
7789            self.fast_first_set_prefilter = false;
7790            self.fast_recovery_enabled = false;
7791            let clean_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7792            let clean_selected = if needs_tree_retry {
7793                match clean_retry {
7794                    ok @ Ok(_) => ok,
7795                    Err(_) => first_pass,
7796                }
7797            } else {
7798                select_better_top_outcome(first_pass, clean_retry, &self.recognition_arena)
7799            };
7800            let selected = if clean_selected.is_err()
7801                || matches!(&clean_selected, Ok((outcome, _, _)) if !outcome.diagnostics.is_empty())
7802            {
7803                self.fast_recovery_enabled = true;
7804                let recovery_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7805                select_better_top_outcome(clean_selected, recovery_retry, &self.recognition_arena)
7806            } else {
7807                clean_selected
7808            };
7809            self.fast_first_set_prefilter = true;
7810            self.fast_recovery_enabled = true;
7811            selected.map_err(|expected| {
7812                if predicate_context.is_some()
7813                    && let Some(error) = self.unknown_semantic_error()
7814                {
7815                    self.report_token_source_errors();
7816                    return error;
7817                }
7818                let error = self.recognition_error(rule_index, start_index, &expected);
7819                self.record_syntax_errors(1);
7820                self.report_token_source_errors();
7821                if report_unrecovered_error {
7822                    self.report_unrecovered_parser_error(&error);
7823                }
7824                error
7825            })?
7826        } else {
7827            first_pass.expect("first_pass is Ok in the no-retry branch")
7828        };
7829        if predicate_context.is_some()
7830            && let Some(error) = self.unknown_semantic_error()
7831        {
7832            self.report_token_source_errors();
7833            return Err(error);
7834        }
7835        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
7836        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
7837        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
7838        self.report_token_source_errors();
7839        let mut context = ParserRuleContext::with_child_capacity(
7840            rule_index,
7841            self.state(),
7842            if self.build_parse_trees {
7843                self.recognition_arena.sequence_len(outcome.nodes)
7844            } else {
7845                0
7846            },
7847        );
7848        if alt_tracking.public {
7849            context.set_alt_number(alt_number.max(1));
7850        }
7851        if alt_tracking.context {
7852            context.set_context_alt_number(alt_number);
7853        }
7854        if let Some(token) = self.token_id_at(start_index) {
7855            self.set_context_start(&mut context, token);
7856        }
7857        let stop_index = self.rule_stop_token_index(outcome.index, outcome.consumed_eof);
7858        if let Some(token) = stop_index.and_then(|token_index| self.token_id_at(token_index)) {
7859            self.set_context_stop(&mut context, token);
7860        }
7861        let live_root = if self.build_parse_trees {
7862            self.recognition_arena
7863                .fold_left_recursive_boundaries(outcome.nodes)
7864        } else {
7865            outcome.nodes
7866        };
7867        if self.build_parse_trees {
7868            if self
7869                .recognition_arena
7870                .sequence_has_explicit_token(live_root)
7871            {
7872                let mut cursor = live_root;
7873                while let Some(link) = self.recognition_arena.link(cursor) {
7874                    let child = self.arena_recognized_node_tree(
7875                        link.head,
7876                        alt_tracking.public,
7877                        alt_tracking.context,
7878                    )?;
7879                    self.tree.add_child(&mut context, child);
7880                    cursor = link.tail;
7881                }
7882            } else {
7883                self.add_arena_implicit_token_children(
7884                    &mut context,
7885                    start_index,
7886                    stop_index,
7887                    live_root,
7888                    alt_tracking,
7889                )?;
7890            }
7891        }
7892        self.finish_recognition_arena(live_root, outcome.diagnostics);
7893        self.input.seek(outcome.index);
7894
7895        let tree = self.rule_node(context);
7896        self.release_tree_scratch_if_idle();
7897        Ok(tree)
7898    }
7899
7900    fn pending_invoking_follow_state(&self, atn: &Atn) -> Option<usize> {
7901        let invoking_state = self.pending_invoking_states.last().copied()?;
7902        let state_number = usize::try_from(invoking_state).ok()?;
7903        match atn.state(state_number)?.transitions().first()?.data() {
7904            Transition::Rule { follow_state, .. } => Some(follow_state),
7905            _ => None,
7906        }
7907    }
7908
7909    #[cfg(test)]
7910    fn caller_follow_token_info(&mut self, index: usize) -> (i32, bool, bool) {
7911        caller_follow_token_info_for_stream(&mut self.input, index)
7912    }
7913
7914    /// Runs the fast recognizer once from the rule's start state and returns
7915    /// the best outcome or the per-attempt expected-token accumulator. The
7916    /// caller flips `fast_first_set_prefilter` between calls when a retry is
7917    /// needed, so the FIRST-set cache is left intact across both passes.
7918    fn fast_recognize_top(
7919        &mut self,
7920        atn: &Atn,
7921        request: FastRecognizeTopRequest,
7922        predicate_context: Option<FastPredicateContext<'_>>,
7923    ) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
7924        let FastRecognizeTopRequest {
7925            start_state,
7926            stop_state,
7927            start_index,
7928            precedence,
7929            caller_follow_state,
7930        } = request;
7931        // `input.size()` is intentionally only the currently buffered token
7932        // count here. Do not restore an up-front fill just to size this map:
7933        // a small floor avoids tiny-input churn, and larger inputs reserve from
7934        // the buffered token count without forcing startup tokenization. The
7935        // 8x multiplier matches the empirical
7936        // memo-insert / token ratio on heavy grammars (C# averages ~6× and
7937        // Kotlin ~12× memo entries per token), so the table avoids one
7938        // rehash on the typical hot path.
7939        let memo_capacity = fast_recognize_memo_capacity(self.input.size());
7940        let mut recognize_scratch = std::mem::take(&mut self.fast_recognize_scratch);
7941        recognize_scratch.prepare(memo_capacity);
7942        let mut expected = ExpectedTokens::default();
7943        let empty_recovery = self.empty_recovery_symbols();
7944        let outcomes = self.recognize_state_fast(
7945            atn,
7946            FastRecognizeRequest {
7947                state_number: start_state,
7948                stop_state,
7949                index: start_index,
7950                rule_start_index: start_index,
7951                decision_start_index: None,
7952                precedence,
7953                depth: 0,
7954                recovery_symbols: empty_recovery,
7955                recovery_state: None,
7956            },
7957            FastRecognizeScratch {
7958                predicate_context,
7959                visiting: &mut recognize_scratch.visiting,
7960                memo: &mut recognize_scratch.memo,
7961                expected: &mut expected,
7962                native_depth: 0,
7963            },
7964        );
7965        recognize_scratch.release_oversized_memo();
7966        self.fast_recognize_scratch = recognize_scratch;
7967        #[cfg(feature = "perf-counters")]
7968        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
7969            perf_counters::dump();
7970            perf_counters::reset();
7971        }
7972        let caller_follow =
7973            caller_follow_state.map(|state| self.cached_state_expected_token_set(atn, state));
7974        let selected = {
7975            let arena = &self.recognition_arena;
7976            let input = &mut self.input;
7977            select_best_fast_outcome(
7978                outcomes.into_iter(),
7979                self.prediction_mode,
7980                caller_follow.as_deref(),
7981                |index| caller_follow_token_info_for_stream(input, index),
7982                arena,
7983            )
7984        };
7985        match selected {
7986            Some(mut outcome) => {
7987                let alt_number = if self.build_parse_trees || self.fast_track_alt_numbers {
7988                    self.materialize_fast_outcome_nodes(&mut outcome)
7989                } else {
7990                    0
7991                };
7992                Ok((outcome, expected, alt_number))
7993            }
7994            None => Err(expected),
7995        }
7996    }
7997
7998    /// Converts one speculative arena record into the flat public CST.
7999    fn arena_recognized_node_tree(
8000        &mut self,
8001        node_id: RecognizedNodeId,
8002        track_alt_numbers: bool,
8003        track_context_alt_numbers: bool,
8004    ) -> Result<ParseTree, AntlrError> {
8005        let node = self.recognition_arena.node(node_id);
8006        match node {
8007            ArenaRecognizedNode::Token { token } => Ok(self.terminal_tree(token)),
8008            ArenaRecognizedNode::ErrorToken { token } => Ok(self.error_tree(token)),
8009            ArenaRecognizedNode::MissingToken { extra } => {
8010                let (token_type, at_index, text) = match self.recognition_arena.extra(extra) {
8011                    RecognitionExtra::MissingToken {
8012                        token_type,
8013                        at_index,
8014                        text,
8015                    } => (*token_type, *at_index as usize, text.clone()),
8016                    RecognitionExtra::ReturnValues(_) | RecognitionExtra::Diagnostic(_) => {
8017                        unreachable!("missing-token node must reference missing-token extra")
8018                    }
8019                };
8020                let (line, column) = self
8021                    .token_at(at_index)
8022                    .map_or((0, 0), |token| (token.line(), token.column()));
8023                let token = self.insert_synthetic_token(token_type, text, line, column)?;
8024                Ok(self.error_tree(token))
8025            }
8026            ArenaRecognizedNode::Rule {
8027                rule_index,
8028                invoking_state,
8029                alt_number,
8030                start_index,
8031                stop_index,
8032                return_values,
8033                children,
8034            } => {
8035                let mut context = ParserRuleContext::with_child_capacity(
8036                    rule_index as usize,
8037                    invoking_state as isize,
8038                    self.recognition_arena.sequence_len(children),
8039                );
8040                if track_alt_numbers {
8041                    context.set_alt_number((alt_number as usize).max(1));
8042                }
8043                if track_context_alt_numbers {
8044                    context.set_context_alt_number(alt_number as usize);
8045                }
8046                if let Some(extra) = return_values {
8047                    let RecognitionExtra::ReturnValues(values) =
8048                        self.recognition_arena.extra(extra)
8049                    else {
8050                        unreachable!("rule node must reference return-values extra");
8051                    };
8052                    for (name, value) in values {
8053                        context.set_int_return(name.clone(), *value);
8054                    }
8055                }
8056                if let Some(token) = self.token_id_at(start_index as usize) {
8057                    self.set_context_start(&mut context, token);
8058                }
8059                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
8060                    self.set_context_stop(&mut context, token);
8061                }
8062                let mut cursor = self
8063                    .recognition_arena
8064                    .fold_left_recursive_boundaries(children);
8065                while let Some(link) = self.recognition_arena.link(cursor) {
8066                    let child = self.arena_recognized_node_tree(
8067                        link.head,
8068                        track_alt_numbers,
8069                        track_context_alt_numbers,
8070                    )?;
8071                    self.tree.add_child(&mut context, child);
8072                    cursor = link.tail;
8073                }
8074                Ok(self.rule_node(context))
8075            }
8076            ArenaRecognizedNode::LeftRecursiveBoundary { rule_index, .. } => {
8077                Err(AntlrError::Unsupported(format!(
8078                    "unfolded left-recursive boundary for rule {rule_index}"
8079                )))
8080            }
8081        }
8082    }
8083
8084    fn arena_recognized_node_tree_with_implicit_tokens(
8085        &mut self,
8086        node_id: RecognizedNodeId,
8087        alt_tracking: AltNumberTracking,
8088    ) -> Result<ParseTree, AntlrError> {
8089        let node = self.recognition_arena.node(node_id);
8090        match node {
8091            ArenaRecognizedNode::Rule {
8092                rule_index,
8093                invoking_state,
8094                alt_number,
8095                start_index,
8096                stop_index,
8097                children,
8098                ..
8099            } => {
8100                let mut context = ParserRuleContext::with_child_capacity(
8101                    rule_index as usize,
8102                    invoking_state as isize,
8103                    self.recognition_arena.sequence_len(children),
8104                );
8105                if alt_tracking.public {
8106                    context.set_alt_number((alt_number as usize).max(1));
8107                }
8108                if alt_tracking.context {
8109                    context.set_context_alt_number(alt_number as usize);
8110                }
8111                if let Some(token) = self.token_id_at(start_index as usize) {
8112                    self.set_context_start(&mut context, token);
8113                }
8114                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
8115                    self.set_context_stop(&mut context, token);
8116                }
8117                let children = self
8118                    .recognition_arena
8119                    .fold_left_recursive_boundaries(children);
8120                self.add_arena_implicit_token_children(
8121                    &mut context,
8122                    start_index as usize,
8123                    stop_index.map(|index| index as usize),
8124                    children,
8125                    alt_tracking,
8126                )?;
8127                Ok(self.rule_node(context))
8128            }
8129            _ => {
8130                self.arena_recognized_node_tree(node_id, alt_tracking.public, alt_tracking.context)
8131            }
8132        }
8133    }
8134
8135    fn add_arena_implicit_token_children(
8136        &mut self,
8137        context: &mut ParserRuleContext,
8138        start_index: usize,
8139        stop_index: Option<usize>,
8140        mut children: NodeSeqId,
8141        alt_tracking: AltNumberTracking,
8142    ) -> Result<(), AntlrError> {
8143        let mut cursor = Some(start_index);
8144        while let Some(link) = self.recognition_arena.link(children) {
8145            if let Some((child_start, child_stop)) = self.recognition_arena.node_span(link.head) {
8146                self.add_visible_terminals_before(context, &mut cursor, child_start)?;
8147                let child =
8148                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
8149                self.tree.add_child(context, child);
8150                if let Some(child_stop) = child_stop {
8151                    let next = self.next_visible_after_token(child_stop);
8152                    cursor = match (cursor, next) {
8153                        (None, _) | (_, None) => None,
8154                        (Some(current), Some(next)) => Some(current.max(next)),
8155                    };
8156                }
8157            } else {
8158                let child =
8159                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
8160                self.tree.add_child(context, child);
8161            }
8162            children = link.tail;
8163        }
8164        if let Some(stop) = stop_index {
8165            self.add_visible_terminals_through(context, cursor, stop)?;
8166        }
8167        Ok(())
8168    }
8169
8170    fn add_visible_terminals_before(
8171        &mut self,
8172        context: &mut ParserRuleContext,
8173        cursor: &mut Option<usize>,
8174        before: usize,
8175    ) -> Result<(), AntlrError> {
8176        let Some(stop) = before.checked_sub(1) else {
8177            return Ok(());
8178        };
8179        let next = self.add_visible_terminals_through(context, *cursor, stop)?;
8180        *cursor = next;
8181        Ok(())
8182    }
8183
8184    fn add_visible_terminals_through(
8185        &mut self,
8186        context: &mut ParserRuleContext,
8187        mut cursor: Option<usize>,
8188        stop: usize,
8189    ) -> Result<Option<usize>, AntlrError> {
8190        while let Some(index) = cursor {
8191            if index > stop {
8192                return Ok(Some(index));
8193            }
8194            let token = self
8195                .input
8196                .get_id(index)
8197                .ok_or_else(|| AntlrError::ParserError {
8198                    line: 0,
8199                    column: 0,
8200                    message: format!("missing token at index {index}"),
8201                    offending: None,
8202                })?;
8203            let is_eof = self.token_type_for_id(token) == TOKEN_EOF;
8204            let child = self.terminal_tree(token);
8205            self.tree.add_child(context, child);
8206            if is_eof {
8207                return Ok(None);
8208            }
8209            cursor = self.next_visible_after_token(index);
8210        }
8211        Ok(None)
8212    }
8213
8214    fn next_visible_after_token(&mut self, index: usize) -> Option<usize> {
8215        let next = self.input.next_visible_after(index);
8216        (next != index).then_some(next)
8217    }
8218
8219    /// Parses a generated rule and returns semantic actions reached on the
8220    /// selected ATN path.
8221    ///
8222    /// This slower path preserves action ordering and token intervals for
8223    /// generated code that replays target-specific action templates after the
8224    /// recognizer has chosen one viable parse path.
8225    pub fn parse_atn_rule_with_actions(
8226        &mut self,
8227        atn: &Atn,
8228        rule_index: usize,
8229    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8230        self.parse_atn_rule_with_action_options(atn, rule_index, &[], false)
8231    }
8232
8233    /// Parses a generated rule and emits ATN actions plus selected rule-init
8234    /// actions reached on the chosen path.
8235    ///
8236    /// Generated parsers use this when a grammar contains rule-level `@init`
8237    /// templates that must run for nested rule invocations. The runtime keeps
8238    /// the action list path-sensitive, so init templates are replayed only for
8239    /// rules that were actually entered by the selected parse.
8240    pub fn parse_atn_rule_with_action_inits(
8241        &mut self,
8242        atn: &Atn,
8243        rule_index: usize,
8244        init_action_rules: &[usize],
8245    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8246        self.parse_atn_rule_with_action_options(atn, rule_index, init_action_rules, false)
8247    }
8248
8249    /// Parses a generated rule with optional semantic-action replay features.
8250    ///
8251    /// `track_alt_numbers` is used by grammars that opt into ANTLR's
8252    /// alt-numbered context behavior. It keeps ordinary parse-tree rendering
8253    /// unchanged for grammars that do not request that target template.
8254    pub fn parse_atn_rule_with_action_options(
8255        &mut self,
8256        atn: &Atn,
8257        rule_index: usize,
8258        init_action_rules: &[usize],
8259        track_alt_numbers: bool,
8260    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8261        self.parse_atn_rule_with_runtime_options(
8262            atn,
8263            rule_index,
8264            ParserRuntimeOptions {
8265                init_action_rules,
8266                track_alt_numbers,
8267                ..ParserRuntimeOptions::default()
8268            },
8269        )
8270    }
8271
8272    /// Parses a generated rule with action replay and parser predicate support.
8273    ///
8274    /// `predicates` maps serialized `(rule_index, pred_index)` coordinates to
8275    /// target-template predicate semantics emitted by the generator. Missing
8276    /// entries are treated as true so unsupported predicate-free grammars keep
8277    /// the previous unconditional transition behavior.
8278    pub fn parse_atn_rule_with_runtime_options(
8279        &mut self,
8280        atn: &Atn,
8281        rule_index: usize,
8282        options: ParserRuntimeOptions<'_>,
8283    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8284        self.parse_atn_rule_with_runtime_options_and_precedence(atn, rule_index, 0, options)
8285    }
8286
8287    fn parse_atn_rule_committed_with_runtime_options(
8288        &mut self,
8289        atn: &Atn,
8290        rule_index: usize,
8291        precedence: i32,
8292        options: ParserRuntimeOptions<'_>,
8293    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8294        let top_level_entry = self.is_top_level_entry();
8295        self.unknown_predicate_policy = options.unknown_predicate_policy;
8296        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8297        let prior_unhandled_action_hits = std::mem::take(&mut self.unhandled_action_hits);
8298        self.clear_prediction_diagnostics();
8299        self.reset_per_parse_caches();
8300        self.reset_recognition_arena();
8301
8302        let mut decision_by_state = vec![None; atn.states().len()];
8303        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
8304            if let Some(slot) = decision_by_state.get_mut(state_number) {
8305                *slot = Some(decision);
8306            }
8307        }
8308        let mut action_index_by_state = FxHashMap::default();
8309        for &(state, index) in options.action_indices {
8310            action_index_by_state.entry(state).or_insert(index);
8311        }
8312        let mut simulator = ParserAtnSimulator::new(atn);
8313        simulator.set_track_prediction_rule_calls(!options.rule_args.is_empty());
8314        let (result, deferred_actions) = {
8315            let mut committed = CommittedAtnParser {
8316                parser: self,
8317                atn,
8318                simulator,
8319                options,
8320                decision_by_state,
8321                action_index_by_state,
8322                deferred_actions: Vec::new(),
8323            };
8324            let result = committed.parse_rule(rule_index, precedence, None, None);
8325            (result, committed.deferred_actions)
8326        };
8327
8328        if top_level_entry {
8329            self.report_generated_parser_diagnostics();
8330        }
8331        let semantic_error = self.unknown_semantic_error();
8332        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8333        self.restore_prior_unhandled_action_hits(prior_unhandled_action_hits);
8334        if top_level_entry && let Some(error) = self.take_parse_abort() {
8335            self.reset_unknown_semantic_hits();
8336            return Err(error);
8337        }
8338        if let Some(error) = semantic_error {
8339            if top_level_entry {
8340                self.reset_unknown_semantic_hits();
8341            }
8342            return Err(error);
8343        }
8344        let result = result.map(|outcome| (outcome.tree, deferred_actions));
8345        if top_level_entry && let Err(error) = &result {
8346            self.report_unrecovered_parser_error(error);
8347        }
8348        result
8349    }
8350
8351    /// Parses a generated rule with action replay, parser predicate support,
8352    /// and an initial left-recursive precedence threshold.
8353    pub fn parse_atn_rule_with_runtime_options_and_precedence(
8354        &mut self,
8355        atn: &Atn,
8356        rule_index: usize,
8357        precedence: i32,
8358        options: ParserRuntimeOptions<'_>,
8359    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8360        if !options.action_indices.is_empty() {
8361            return self.parse_atn_rule_committed_with_runtime_options(
8362                atn, rule_index, precedence, options,
8363            );
8364        }
8365        let report_unrecovered_error = self.is_top_level_entry();
8366        let ParserRuntimeOptions {
8367            init_action_rules,
8368            track_alt_numbers,
8369            track_context_alt_numbers,
8370            predicates,
8371            semantics,
8372            rule_args,
8373            member_actions,
8374            return_actions,
8375            unknown_predicate_policy,
8376            ..
8377        } = options;
8378        let capture_alt_numbers = track_alt_numbers || track_context_alt_numbers;
8379        if init_action_rules.is_empty()
8380            && !capture_alt_numbers
8381            && predicates.is_empty()
8382            && semantics.is_none()
8383            && rule_args.is_empty()
8384            && member_actions.is_empty()
8385            && return_actions.is_empty()
8386            && unknown_predicate_policy == UnknownSemanticPolicy::AssumeTrue
8387            && !atn_has_observable_action_transitions(atn)
8388            && !self.semantic_hooks.observes_parser_decisions()
8389            && (!self.semantic_hooks.observes_parser_predicates()
8390                || !atn_has_predicate_transitions(atn))
8391        {
8392            return self
8393                .parse_atn_rule_with_precedence(atn, rule_index, precedence)
8394                .map(|tree| (tree, Vec::new()));
8395        }
8396        if !self.semantic_hooks.observes_parser_decisions()
8397            && can_use_fast_predicate_recognizer(atn, &options)
8398        {
8399            self.unknown_predicate_policy = unknown_predicate_policy;
8400            let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8401            let member_values = self.int_members.clone();
8402            let result = self
8403                .parse_atn_rule_with_precedence_inner(
8404                    atn,
8405                    rule_index,
8406                    precedence,
8407                    Some(FastPredicateContext {
8408                        predicates,
8409                        semantics,
8410                        member_values: &member_values,
8411                    }),
8412                    AltNumberTracking {
8413                        public: track_alt_numbers,
8414                        context: track_context_alt_numbers,
8415                    },
8416                )
8417                .map(|tree| (tree, Vec::new()));
8418            if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
8419                self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8420            }
8421            return result;
8422        }
8423        self.unknown_predicate_policy = unknown_predicate_policy;
8424        // A generated parent may have already recorded unknown-predicate
8425        // coordinates before descending into this (interpreted) child. Clearing
8426        // unconditionally would drop them before the parent's public entry
8427        // surfaces them, so stash and restore around this call: recognition sees
8428        // only the hits it records itself (so the fail-loud check below reflects
8429        // this rule), and the parent's prior hits are merged back afterward.
8430        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8431        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
8432            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
8433        })?;
8434        let stop_state = atn
8435            .rule_to_stop_state()
8436            .get(rule_index)
8437            .filter(|state| *state != usize::MAX)
8438            .ok_or_else(|| {
8439                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
8440            })?;
8441
8442        let start_index = self.current_visible_index();
8443        self.clear_prediction_diagnostics();
8444        self.reset_per_parse_caches();
8445        self.reset_recognition_arena();
8446        let init_action_rules = init_action_rules.iter().copied().collect::<BTreeSet<_>>();
8447        let invoking_state = self.pending_invoking_states.pop();
8448        let local_int_arg = invoking_state
8449            .and_then(|state| usize::try_from(state).ok())
8450            .and_then(|state| rule_local_int_arg(rule_args, state, rule_index, None));
8451        let mut visiting = BTreeSet::new();
8452        let mut memo = BTreeMap::new();
8453        let mut expected = ExpectedTokens::default();
8454        let member_values = self.int_members.clone();
8455        let return_values = BTreeMap::new();
8456        let outcomes = self.recognize_state(
8457            atn,
8458            RecognizeRequest {
8459                state_number: start_state,
8460                stop_state,
8461                index: start_index,
8462                rule_start_index: start_index,
8463                decision_start_index: None,
8464                init_action_rules: &init_action_rules,
8465                predicates,
8466                semantics,
8467                rule_args,
8468                member_actions,
8469                return_actions,
8470                local_int_arg,
8471                member_values,
8472                return_values,
8473                rule_alt_number: 0,
8474                track_alt_numbers: capture_alt_numbers,
8475                consumed_eof: false,
8476                committed_decision: false,
8477                precedence,
8478                depth: 0,
8479                recovery_symbols: BTreeSet::new(),
8480                recovery_state: None,
8481            },
8482            &mut visiting,
8483            &mut memo,
8484            &mut expected,
8485        );
8486        if let Some(error) = self.unknown_semantic_error() {
8487            self.report_token_source_errors();
8488            // Keep the recorded coordinates: when this interpreted rule is a
8489            // child of a generated parent, the parent's catch block recovers an
8490            // ordinary `AntlrError` into a partial subtree, so the fail-loud
8491            // coordinate must survive on the parser for the top-level entry's
8492            // `take_unknown_semantic_error` to surface it. Cross-parse staleness
8493            // is handled by clearing at the top-level generated entry instead.
8494            return Err(error);
8495        }
8496        // Recognition recorded no unresolved coordinate of its own; merge the
8497        // parent's prior hits back so its public entry can still surface them.
8498        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8499        let Some(outcome) = select_best_outcome(
8500            outcomes.into_iter(),
8501            self.prediction_mode,
8502            &self.recognition_arena,
8503        ) else {
8504            let error = self.recognition_error(rule_index, start_index, &expected);
8505            self.record_syntax_errors(1);
8506            self.report_token_source_errors();
8507            if report_unrecovered_error {
8508                self.report_unrecovered_parser_error(&error);
8509            }
8510            return Err(error);
8511        };
8512
8513        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
8514        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
8515        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
8516        self.report_token_source_errors();
8517        let mut actions = outcome.actions;
8518        if init_action_rules.contains(&rule_index) {
8519            actions.insert(
8520                0,
8521                ParserAction::new_rule_init(rule_index, start_index, Some(start_state)),
8522            );
8523        }
8524        let mut context =
8525            ParserRuleContext::new(rule_index, invoking_state.unwrap_or_else(|| self.state()));
8526        if track_alt_numbers {
8527            context.set_alt_number(outcome.alt_number.max(1));
8528        }
8529        if track_context_alt_numbers {
8530            context.set_context_alt_number(outcome.alt_number);
8531        }
8532        for (name, value) in outcome.return_values {
8533            context.set_int_return(name, value);
8534        }
8535        if let Some(token) = self.token_id_at(start_index) {
8536            self.set_context_start(&mut context, token);
8537        }
8538        if let Some(token) = self.rule_stop_token_id(outcome.index, outcome.consumed_eof) {
8539            self.set_context_stop(&mut context, token);
8540        }
8541        let live_root = if self.build_parse_trees {
8542            self.recognition_arena
8543                .fold_left_recursive_boundaries(outcome.nodes)
8544        } else {
8545            outcome.nodes
8546        };
8547        if self.build_parse_trees {
8548            let mut nodes = live_root;
8549            while let Some(link) = self.recognition_arena.link(nodes) {
8550                let child = self.arena_recognized_node_tree(
8551                    link.head,
8552                    track_alt_numbers,
8553                    track_context_alt_numbers,
8554                )?;
8555                self.tree.add_child(&mut context, child);
8556                nodes = link.tail;
8557            }
8558        }
8559        self.finish_recognition_arena(live_root, outcome.diagnostics);
8560        self.input.seek(outcome.index);
8561
8562        let tree = self.rule_node(context);
8563        self.release_tree_scratch_if_idle();
8564        Ok((tree, actions))
8565    }
8566
8567    /// Temporary parser entry used by generated parser methods while the parser
8568    /// ATN simulator is being implemented.
8569    ///
8570    /// This keeps generated parser crates buildable and gives us a stable method
8571    /// surface for every grammar rule. It intentionally accepts all remaining
8572    /// tokens into one rule context; it is not the final parser semantics.
8573    pub fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<ParseTree, AntlrError> {
8574        let mut context = ParserRuleContext::new(rule_index, self.state());
8575        while self.la(1) != TOKEN_EOF {
8576            let token_type = self.la(1);
8577            let child = self.match_token(token_type)?;
8578            if self.build_parse_trees {
8579                self.tree.add_child(&mut context, child);
8580            }
8581        }
8582        if self.build_parse_trees {
8583            let child = self.match_eof()?;
8584            self.tree.add_child(&mut context, child);
8585        }
8586        let tree = self.rule_node(context);
8587        self.release_tree_scratch_if_idle();
8588        Ok(tree)
8589    }
8590
8591    /// Builds the parser error reported when no ATN path can reach the active
8592    /// rule stop state.
8593    fn recognition_error(
8594        &mut self,
8595        rule_index: usize,
8596        start_index: usize,
8597        expected: &ExpectedTokens,
8598    ) -> AntlrError {
8599        let (index, message) = self.expected_error_message(rule_index, start_index, expected);
8600        self.input.seek(index);
8601        let current = self.input.lt(1);
8602        let line = current.as_ref().map(Token::line).unwrap_or_default();
8603        let column = current.as_ref().map(Token::column).unwrap_or_default();
8604        AntlrError::ParserError {
8605            line,
8606            column,
8607            message,
8608            offending: current.as_ref().map(Token::token_id),
8609        }
8610    }
8611
8612    /// Builds the token index and ANTLR-compatible message for a failed rule.
8613    fn expected_error_message(
8614        &mut self,
8615        rule_index: usize,
8616        start_index: usize,
8617        expected: &ExpectedTokens,
8618    ) -> (usize, String) {
8619        let index = expected
8620            .index
8621            .or_else(|| expected.no_viable.map(|no_viable| no_viable.error_index))
8622            .unwrap_or_else(|| self.input.index());
8623        self.input.seek(index);
8624        let current = self.input.lt(1);
8625        let message = if expected
8626            .no_viable
8627            .as_ref()
8628            .is_some_and(|no_viable| no_viable.error_index == index)
8629        {
8630            let start = expected
8631                .no_viable
8632                .as_ref()
8633                .map_or(start_index, |no_viable| no_viable.start_index);
8634            let text = display_input_text(&self.input.text(start, index));
8635            format!("no viable alternative at input '{text}'")
8636        } else if expected.symbols.is_empty() {
8637            if expected.index.is_some() {
8638                let found = current
8639                    .as_ref()
8640                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display);
8641                if current
8642                    .as_ref()
8643                    .is_some_and(|token| token.token_type() == TOKEN_EOF)
8644                {
8645                    format!(
8646                        "missing {} at {found}",
8647                        self.expected_symbols_display(&expected.symbols)
8648                    )
8649                } else {
8650                    format!("mismatched input {found}")
8651                }
8652            } else {
8653                format!("no viable alternative while parsing rule {rule_index}")
8654            }
8655        } else {
8656            format!(
8657                "mismatched input {} expecting {}",
8658                current
8659                    .as_ref()
8660                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8661                self.expected_symbols_display(&expected.symbols)
8662            )
8663        };
8664        (index, message)
8665    }
8666
8667    /// Converts a failed child rule into a recovered outcome so the parent can
8668    /// continue after reporting the child diagnostic.
8669    fn child_rule_failure_recovery(
8670        &mut self,
8671        rule_index: usize,
8672        start_index: usize,
8673        sync_symbols: &BTreeSet<i32>,
8674        member_values: MemberEnv,
8675        expected: &ExpectedTokens,
8676    ) -> Option<RecognizeOutcome> {
8677        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
8678        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
8679        let mut next_index = error_index;
8680        loop {
8681            let symbol = self.token_type_at(next_index);
8682            if sync_symbols.contains(&symbol) {
8683                if next_index == error_index {
8684                    return None;
8685                }
8686                break;
8687            }
8688            if symbol == TOKEN_EOF {
8689                break;
8690            }
8691            let after = self.consume_index(next_index, symbol);
8692            if after == next_index {
8693                break;
8694            }
8695            next_index = after;
8696        }
8697        let mut nodes = NodeSeqId::EMPTY;
8698        let error = self.arena_token_node(error_index, true);
8699        self.arena_prepend(&mut nodes, error);
8700        let diagnostics = self
8701            .recognition_arena
8702            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
8703        Some(RecognizeOutcome {
8704            index: next_index,
8705            consumed_eof: false,
8706            alt_number: 0,
8707            member_values,
8708            return_values: BTreeMap::new(),
8709            diagnostics,
8710            decisions: Vec::new(),
8711            actions: Vec::new(),
8712            nodes,
8713        })
8714    }
8715
8716    /// Adapts the optional recovery result to the normal outcome list used by
8717    /// rule-call transitions.
8718    fn child_rule_failure_recovery_outcomes(
8719        &mut self,
8720        request: ChildRuleFailureRecovery<'_>,
8721    ) -> Vec<RecognizeOutcome> {
8722        let sync_symbols =
8723            state_sync_symbols(request.atn, request.follow_state, request.stop_state);
8724        self.child_rule_failure_recovery(
8725            request.rule_index,
8726            request.start_index,
8727            &sync_symbols,
8728            request.member_values,
8729            request.expected,
8730        )
8731        .into_iter()
8732        .collect()
8733    }
8734
8735    /// Formats expected token types using ANTLR's single-token or set syntax.
8736    fn expected_symbols_display(&self, symbols: &BTreeSet<i32>) -> String {
8737        expected_symbols_display(symbols, self.vocabulary())
8738    }
8739
8740    /// Returns the single-token deletion repair if the token after `index`
8741    /// satisfies the failed consuming transition.
8742    fn single_token_deletion(
8743        &mut self,
8744        transition: ParserTransition<'_>,
8745        index: usize,
8746        max_token_type: i32,
8747        expected_symbols: &BTreeSet<i32>,
8748    ) -> Option<(ParserDiagnostic, usize, i32)> {
8749        let current_symbol = self.token_type_at(index);
8750        if current_symbol == TOKEN_EOF {
8751            return None;
8752        }
8753        let next_index = self.consume_index(index, current_symbol);
8754        if next_index == index {
8755            return None;
8756        }
8757        let next_symbol = self.token_type_at(next_index);
8758        if !transition.matches(next_symbol, 1, max_token_type) {
8759            return None;
8760        }
8761        let transition_expected = transition_expected_symbols(transition, max_token_type);
8762        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8763            &transition_expected
8764        } else {
8765            expected_symbols
8766        });
8767        let current = self.token_at(index);
8768        let message = format!(
8769            "extraneous input {} expecting {expected_display}",
8770            current
8771                .as_ref()
8772                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8773        );
8774        Some((
8775            diagnostic_for_token(current, message),
8776            next_index,
8777            next_symbol,
8778        ))
8779    }
8780
8781    /// Returns the repair used when deleting the current token lets a recovery
8782    /// state continue with the following token.
8783    fn current_token_deletion(
8784        &mut self,
8785        index: usize,
8786        expected_symbols: &BTreeSet<i32>,
8787    ) -> Option<(ParserDiagnostic, usize, Vec<usize>)> {
8788        if expected_symbols.is_empty() {
8789            return None;
8790        }
8791        let current_symbol = self.token_type_at(index);
8792        if current_symbol == TOKEN_EOF {
8793            return None;
8794        }
8795        let current = self.token_at(index);
8796        let message = format!(
8797            "extraneous input {} expecting {}",
8798            current
8799                .as_ref()
8800                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8801            self.expected_symbols_display(expected_symbols)
8802        );
8803        let diagnostic = diagnostic_for_token(current, message);
8804        let mut skipped = Vec::new();
8805        let mut cursor = index;
8806        loop {
8807            let symbol = self.token_type_at(cursor);
8808            if symbol == TOKEN_EOF {
8809                return None;
8810            }
8811            skipped.push(cursor);
8812            let next_index = self.consume_index(cursor, symbol);
8813            if next_index == cursor {
8814                return None;
8815            }
8816            let next_symbol = self.token_type_at(next_index);
8817            if expected_symbols.contains(&next_symbol) {
8818                return Some((diagnostic, next_index, skipped));
8819            }
8820            cursor = next_index;
8821        }
8822    }
8823
8824    /// Returns the single-token insertion repair for a failed consuming
8825    /// transition. The caller validates the repair by continuing from the
8826    /// transition target at the same input index.
8827    fn single_token_insertion(
8828        &mut self,
8829        transition: ParserTransition<'_>,
8830        index: usize,
8831        max_token_type: i32,
8832        expected_symbols: &BTreeSet<i32>,
8833        follow_symbols: &BTreeSet<i32>,
8834    ) -> Option<(ParserDiagnostic, i32, String)> {
8835        let current_symbol = self.token_type_at(index);
8836        if !follow_symbols.contains(&current_symbol) {
8837            return None;
8838        }
8839        let transition_expected = transition_expected_symbols(transition, max_token_type);
8840        let token_type = transition_expected.iter().next().copied()?;
8841        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8842            &transition_expected
8843        } else {
8844            expected_symbols
8845        });
8846        let mut token_symbols = BTreeSet::new();
8847        token_symbols.insert(token_type);
8848        let missing_token_display = self.expected_symbols_display(&token_symbols);
8849        let current = self.token_at(index);
8850        let message = format!(
8851            "missing {expected_display} at {}",
8852            current
8853                .as_ref()
8854                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8855        );
8856        let text = format!("<missing {missing_token_display}>");
8857        Some((
8858            diagnostic_for_token(current.as_ref(), message),
8859            token_type,
8860            text,
8861        ))
8862    }
8863
8864    /// Explores ANTLR's single-token deletion recovery for the fast recognizer:
8865    /// skip the unexpected current token when the following token satisfies the
8866    /// transition that failed.
8867    fn fast_single_token_deletion_recovery(
8868        &mut self,
8869        recovery: FastRecoveryRequest<'_, '_>,
8870        predicate_context: Option<FastPredicateContext<'_>>,
8871    ) -> Vec<FastRecognizeOutcome> {
8872        let FastRecoveryRequest {
8873            atn,
8874            transition,
8875            expected_symbols,
8876            target,
8877            request,
8878            visiting,
8879            memo,
8880            expected,
8881        } = recovery;
8882        let FastRecognizeRequest {
8883            stop_state,
8884            index,
8885            rule_start_index,
8886            decision_start_index,
8887            precedence,
8888            depth,
8889            ..
8890        } = request;
8891        let Some((diagnostic, next_index, next_symbol)) =
8892            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
8893        else {
8894            return Vec::new();
8895        };
8896        let after_next = self.consume_index(next_index, next_symbol);
8897        let empty_recovery = self.empty_recovery_symbols();
8898        self.recognize_state_fast(
8899            atn,
8900            FastRecognizeRequest {
8901                state_number: target,
8902                stop_state,
8903                index: after_next,
8904                rule_start_index,
8905                decision_start_index,
8906                precedence,
8907                depth: depth + 1,
8908                recovery_symbols: empty_recovery,
8909                recovery_state: None,
8910            },
8911            FastRecognizeScratch {
8912                predicate_context,
8913                visiting,
8914                memo,
8915                expected,
8916                native_depth: 0,
8917            },
8918        )
8919        .into_iter()
8920        .map(|mut outcome| {
8921            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
8922            outcome.diagnostics = self
8923                .recognition_arena
8924                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8925            if self.fast_token_nodes_enabled {
8926                let token = self.arena_token_node(next_index, false);
8927                self.defer_fast_outcome_node(&mut outcome, token);
8928                let error = self.arena_token_node(index, true);
8929                self.defer_fast_outcome_node(&mut outcome, error);
8930            }
8931            outcome
8932        })
8933        .collect()
8934    }
8935
8936    /// Explores ANTLR's single-token insertion recovery for the fast recognizer:
8937    /// pretend the expected transition token was present and continue without
8938    /// consuming the current token.
8939    fn fast_single_token_insertion_recovery(
8940        &mut self,
8941        recovery: FastRecoveryRequest<'_, '_>,
8942        predicate_context: Option<FastPredicateContext<'_>>,
8943    ) -> Vec<FastRecognizeOutcome> {
8944        let FastRecoveryRequest {
8945            atn,
8946            transition,
8947            expected_symbols,
8948            target,
8949            request,
8950            visiting,
8951            memo,
8952            expected,
8953        } = recovery;
8954        let FastRecognizeRequest {
8955            stop_state,
8956            index,
8957            rule_start_index,
8958            decision_start_index,
8959            precedence,
8960            depth,
8961            ..
8962        } = request;
8963        let follow_symbols = self.cached_state_expected_symbols(atn, transition.target());
8964        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
8965            transition,
8966            index,
8967            atn.max_token_type(),
8968            &expected_symbols,
8969            &follow_symbols,
8970        ) else {
8971            return Vec::new();
8972        };
8973        let empty_recovery = self.empty_recovery_symbols();
8974        self.recognize_state_fast(
8975            atn,
8976            FastRecognizeRequest {
8977                state_number: target,
8978                stop_state,
8979                index,
8980                rule_start_index,
8981                decision_start_index,
8982                precedence,
8983                depth: depth + 1,
8984                recovery_symbols: empty_recovery,
8985                recovery_state: None,
8986            },
8987            FastRecognizeScratch {
8988                predicate_context,
8989                visiting,
8990                memo,
8991                expected,
8992                native_depth: 0,
8993            },
8994        )
8995        .into_iter()
8996        .map(|mut outcome| {
8997            outcome.diagnostics = self
8998                .recognition_arena
8999                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9000            let missing = self.arena_missing_token_node(token_type, index, text.clone());
9001            self.defer_fast_outcome_node(&mut outcome, missing);
9002            outcome
9003        })
9004        .collect()
9005    }
9006
9007    /// Retries the current fast-recognition state after deleting one
9008    /// unexpected token that precedes a valid loop or block continuation.
9009    fn fast_current_token_deletion_recovery(
9010        &mut self,
9011        recovery: FastCurrentTokenDeletionRequest<'_, '_>,
9012        predicate_context: Option<FastPredicateContext<'_>>,
9013    ) -> Vec<FastRecognizeOutcome> {
9014        let FastCurrentTokenDeletionRequest {
9015            atn,
9016            expected_symbols,
9017            mut request,
9018            visiting,
9019            memo,
9020            expected,
9021        } = recovery;
9022        if request.index == request.rule_start_index {
9023            return Vec::new();
9024        }
9025        let Some((diagnostic, next_index, skipped)) =
9026            self.current_token_deletion(request.index, &expected_symbols)
9027        else {
9028            return Vec::new();
9029        };
9030        request.state_number = request.recovery_state.unwrap_or(request.state_number);
9031        request.index = next_index;
9032        request.depth += 1;
9033        request.recovery_state = None;
9034        self.recognize_state_fast(
9035            atn,
9036            request,
9037            FastRecognizeScratch {
9038                predicate_context,
9039                visiting,
9040                memo,
9041                expected,
9042                native_depth: 0,
9043            },
9044        )
9045        .into_iter()
9046        .map(|mut outcome| {
9047            outcome.diagnostics = self
9048                .recognition_arena
9049                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9050            for index in skipped.iter().rev() {
9051                let error = self.arena_token_node(*index, true);
9052                self.defer_fast_outcome_node(&mut outcome, error);
9053            }
9054            outcome
9055        })
9056        .collect()
9057    }
9058
9059    /// Converts a failed child rule into a recovered fast-recognizer outcome so
9060    /// the parent can keep its child rule context and continue at a sync token.
9061    fn fast_child_rule_failure_recovery(
9062        &mut self,
9063        rule_index: usize,
9064        start_index: usize,
9065        sync_symbols: &BTreeSet<i32>,
9066        expected: &ExpectedTokens,
9067    ) -> Option<FastRecognizeOutcome> {
9068        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
9069        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
9070        let mut next_index = error_index;
9071        loop {
9072            let symbol = self.token_type_at(next_index);
9073            if sync_symbols.contains(&symbol) {
9074                if next_index == error_index {
9075                    return None;
9076                }
9077                break;
9078            }
9079            if symbol == TOKEN_EOF {
9080                break;
9081            }
9082            let after = self.consume_index(next_index, symbol);
9083            if after == next_index {
9084                break;
9085            }
9086            next_index = after;
9087        }
9088        let diagnostics = self
9089            .recognition_arena
9090            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
9091        let mut nodes = NodeSeqId::EMPTY;
9092        if self.fast_token_nodes_enabled {
9093            let error = self.arena_token_node(error_index, true);
9094            self.arena_prepend(&mut nodes, error);
9095        }
9096        Some(FastRecognizeOutcome {
9097            index: next_index,
9098            consumed_eof: false,
9099            diagnostics,
9100            deferred_nodes: FastDeferredNodeId::EMPTY,
9101            nodes,
9102        })
9103    }
9104
9105    /// Adapts the optional child-rule recovery result to the fast-recognizer
9106    /// outcome list used by rule-call transitions.
9107    fn fast_child_rule_failure_recovery_outcomes(
9108        &mut self,
9109        request: FastChildRuleFailureRecoveryRequest<'_>,
9110    ) -> Vec<FastRecognizeOutcome> {
9111        let FastChildRuleFailureRecoveryRequest {
9112            atn,
9113            rule_index,
9114            start_index,
9115            follow_state,
9116            stop_state,
9117            expected,
9118        } = request;
9119        let sync_symbols = state_sync_symbols(atn, follow_state, stop_state);
9120        self.fast_child_rule_failure_recovery(rule_index, start_index, &sync_symbols, expected)
9121            .into_iter()
9122            .collect()
9123    }
9124
9125    fn defer_fast_outcome_node(
9126        &mut self,
9127        outcome: &mut FastRecognizeOutcome,
9128        node: RecognizedNodeId,
9129    ) {
9130        if outcome.deferred_nodes.is_empty() {
9131            self.arena_prepend(&mut outcome.nodes, node);
9132            return;
9133        }
9134        let fragment = self.recognition_arena.prepend(NodeSeqId::EMPTY, node);
9135        let fragment = self.recognition_arena.deferred_fragment(fragment);
9136        outcome.deferred_nodes = self
9137            .recognition_arena
9138            .concat_deferred_nodes(fragment, outcome.deferred_nodes);
9139    }
9140
9141    fn defer_fast_outcome_alternative(
9142        &mut self,
9143        outcome: &mut FastRecognizeOutcome,
9144        alt_number: usize,
9145    ) {
9146        let alternative = self.recognition_arena.deferred_alternative(alt_number);
9147        outcome.deferred_nodes = self
9148            .recognition_arena
9149            .concat_deferred_nodes(alternative, outcome.deferred_nodes);
9150    }
9151
9152    fn defer_fast_outcome_boundary(
9153        &mut self,
9154        outcome: &mut FastRecognizeOutcome,
9155        rule_index: usize,
9156    ) {
9157        let boundary = self
9158            .recognition_arena
9159            .deferred_left_recursive_boundary(rule_index);
9160        outcome.deferred_nodes = self
9161            .recognition_arena
9162            .concat_deferred_nodes(boundary, outcome.deferred_nodes);
9163    }
9164
9165    fn materialize_fast_deferred_nodes(
9166        &mut self,
9167        root: FastDeferredNodeId,
9168        initial_suffix: NodeSeqId,
9169    ) -> (NodeSeqId, usize) {
9170        if root.is_empty() {
9171            return (initial_suffix, 0);
9172        }
9173
9174        enum Frame {
9175            Visit(FastDeferredNodeId),
9176            ContinuePrefix(FastDeferredNodeId),
9177            FinishRule {
9178                rule: FastDeferredRule,
9179                parent_suffix: NodeSeqId,
9180                parent_alt_number: u32,
9181                parent_pending_boundary: Option<RecognizedNodeId>,
9182            },
9183        }
9184
9185        let mut result = initial_suffix;
9186        // The rope is visited suffix-first while nodes are prepended. Later
9187        // alternatives arrive first, so earlier markers overwrite them; a
9188        // boundary redirects those earlier markers to the wrapped context.
9189        let mut alt_number = 0;
9190        let mut pending_boundary = None;
9191        let mut pending = Vec::with_capacity(16);
9192        pending.push(Frame::Visit(root));
9193        let mut fragment_nodes = Vec::new();
9194        while let Some(frame) = pending.pop() {
9195            match frame {
9196                Frame::Visit(deferred) => {
9197                    if deferred.is_empty() {
9198                        continue;
9199                    }
9200
9201                    match self.recognition_arena.deferred_node(deferred) {
9202                        FastDeferredNode::Fragment(sequence) => {
9203                            fragment_nodes.clear();
9204                            fragment_nodes.extend(self.recognition_arena.iter(sequence));
9205                            while let Some(node) = fragment_nodes.pop() {
9206                                self.arena_prepend(&mut result, node);
9207                            }
9208                        }
9209                        FastDeferredNode::Rule(rule) => {
9210                            let rule = self.recognition_arena.deferred_rule(rule);
9211                            let parent_suffix = result;
9212                            let parent_alt_number = alt_number;
9213                            let parent_pending_boundary = pending_boundary;
9214                            result = rule.children;
9215                            alt_number = 0;
9216                            pending_boundary = None;
9217                            pending.push(Frame::FinishRule {
9218                                rule,
9219                                parent_suffix,
9220                                parent_alt_number,
9221                                parent_pending_boundary,
9222                            });
9223                            pending.push(Frame::Visit(rule.deferred_children));
9224                        }
9225                        FastDeferredNode::Alternative(selected) => {
9226                            if let Some(boundary) = pending_boundary {
9227                                self.recognition_arena
9228                                    .set_boundary_alt_number(boundary, selected);
9229                            } else {
9230                                alt_number = selected;
9231                            }
9232                        }
9233                        FastDeferredNode::LeftRecursiveBoundary { rule_index } => {
9234                            let boundary = self.arena_boundary_node(rule_index as usize, 0);
9235                            self.arena_prepend(&mut result, boundary);
9236                            pending_boundary = Some(boundary);
9237                        }
9238                        FastDeferredNode::Concat {
9239                            prefix,
9240                            suffix: deferred_suffix,
9241                        } => {
9242                            pending.push(Frame::ContinuePrefix(prefix));
9243                            pending.push(Frame::Visit(deferred_suffix));
9244                        }
9245                    }
9246                }
9247                Frame::ContinuePrefix(prefix) => pending.push(Frame::Visit(prefix)),
9248                Frame::FinishRule {
9249                    rule,
9250                    parent_suffix,
9251                    parent_alt_number,
9252                    parent_pending_boundary,
9253                } => {
9254                    let node = self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
9255                        rule_index: rule.rule_index,
9256                        invoking_state: rule.invoking_state,
9257                        alt_number,
9258                        start_index: rule.start_index,
9259                        stop_index: rule.stop_index,
9260                        return_values: None,
9261                        children: result,
9262                    });
9263                    result = parent_suffix;
9264                    self.arena_prepend(&mut result, node);
9265                    alt_number = parent_alt_number;
9266                    pending_boundary = parent_pending_boundary;
9267                }
9268            }
9269        }
9270        (result, alt_number as usize)
9271    }
9272
9273    fn materialize_fast_outcome_nodes(&mut self, outcome: &mut FastRecognizeOutcome) -> usize {
9274        let deferred_nodes = std::mem::take(&mut outcome.deferred_nodes);
9275        let (nodes, alt_number) =
9276            self.materialize_fast_deferred_nodes(deferred_nodes, outcome.nodes);
9277        outcome.nodes = nodes;
9278        alt_number
9279    }
9280
9281    /// Walks one ordinary `*`/`+` repetition at a time so input length grows
9282    /// heap work instead of the native call stack.
9283    fn recognize_repetition_fast(
9284        &mut self,
9285        atn: &Atn,
9286        request: &FastRecognizeRequest,
9287        shape: FastRepetitionShape,
9288        scratch: FastRecognizeScratch<'_, '_>,
9289    ) -> Vec<FastRecognizeOutcome> {
9290        let FastRecognizeScratch {
9291            predicate_context,
9292            visiting,
9293            memo,
9294            expected,
9295            native_depth,
9296        } = scratch;
9297        let lookahead = if self.fast_first_set_prefilter {
9298            atn.state(request.state_number).and_then(|state| {
9299                state
9300                    .rule_index()
9301                    .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9302                    .map(|rule_stop| self.cached_decision_lookahead(atn, state, rule_stop))
9303            })
9304        } else {
9305            None
9306        };
9307        let (enter_alt_number, exit_alt_number) = if self.fast_track_alt_numbers {
9308            let state = atn
9309                .state(request.state_number)
9310                .expect("repetition request state must exist");
9311            (
9312                next_alt_number(state, 2, shape.enter_transition_index, 0, true),
9313                next_alt_number(state, 2, shape.exit_transition_index, 0, true),
9314            )
9315        } else {
9316            (0, 0)
9317        };
9318        let mut work = Vec::with_capacity(2);
9319        push_fast_repetition_work(
9320            &mut work,
9321            shape,
9322            FastRepetitionPath {
9323                index: request.index,
9324                deferred_nodes: FastDeferredNodeId::EMPTY,
9325                diagnostics: DiagnosticSeqId::EMPTY,
9326                consumed_eof: false,
9327            },
9328            lookahead.as_deref(),
9329            self.token_type_at(request.index),
9330        );
9331        let mut coordinates = FastRepetitionCoordinates::new(request.index);
9332        let mut outcomes = Vec::new();
9333        while let Some(item) = work.pop() {
9334            match item {
9335                FastRepetitionWork::Enter(path) => {
9336                    if !coordinates.insert_entered(path) {
9337                        continue;
9338                    }
9339                    let path_nodes = if enter_alt_number == 0 {
9340                        path.deferred_nodes
9341                    } else {
9342                        let alternative = self
9343                            .recognition_arena
9344                            .deferred_alternative(enter_alt_number);
9345                        self.recognition_arena
9346                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9347                    };
9348                    let body_outcomes = self.recognize_state_fast(
9349                        atn,
9350                        FastRecognizeRequest {
9351                            state_number: shape.enter_target,
9352                            stop_state: shape.body_stop_state,
9353                            index: path.index,
9354                            rule_start_index: request.rule_start_index,
9355                            decision_start_index: request.decision_start_index,
9356                            precedence: request.precedence,
9357                            depth: request.depth.saturating_add(1),
9358                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9359                            recovery_state: request.recovery_state,
9360                        },
9361                        FastRecognizeScratch {
9362                            predicate_context,
9363                            visiting: &mut *visiting,
9364                            memo: &mut *memo,
9365                            expected: &mut *expected,
9366                            native_depth: native_depth + 1,
9367                        },
9368                    );
9369                    for body in body_outcomes.into_iter().rev() {
9370                        // ANTLR rejects nullable repetition bodies. Keep the
9371                        // interpreter bounded for malformed or recovered ATNs
9372                        // by mirroring the existing same-coordinate cycle cut.
9373                        if body.index <= path.index {
9374                            continue;
9375                        }
9376                        let body_fragment = self.recognition_arena.deferred_fragment(body.nodes);
9377                        let body_nodes = self
9378                            .recognition_arena
9379                            .concat_deferred_nodes(body.deferred_nodes, body_fragment);
9380                        let deferred_nodes = self
9381                            .recognition_arena
9382                            .concat_deferred_nodes(path_nodes, body_nodes);
9383                        let next_path = FastRepetitionPath {
9384                            index: body.index,
9385                            deferred_nodes,
9386                            diagnostics: self
9387                                .recognition_arena
9388                                .concat_diagnostics(path.diagnostics, body.diagnostics),
9389                            consumed_eof: path.consumed_eof || body.consumed_eof,
9390                        };
9391                        let symbol = self.token_type_at(next_path.index);
9392                        push_fast_repetition_work(
9393                            &mut work,
9394                            shape,
9395                            next_path,
9396                            lookahead.as_deref(),
9397                            symbol,
9398                        );
9399                    }
9400                }
9401                FastRepetitionWork::Exit(path) => {
9402                    if !coordinates.insert_exited(path) {
9403                        continue;
9404                    }
9405                    let path_nodes = if exit_alt_number == 0 {
9406                        path.deferred_nodes
9407                    } else {
9408                        let alternative =
9409                            self.recognition_arena.deferred_alternative(exit_alt_number);
9410                        self.recognition_arena
9411                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9412                    };
9413                    let suffixes = self.recognize_state_fast(
9414                        atn,
9415                        FastRecognizeRequest {
9416                            state_number: shape.exit_target,
9417                            stop_state: request.stop_state,
9418                            index: path.index,
9419                            rule_start_index: request.rule_start_index,
9420                            decision_start_index: request.decision_start_index,
9421                            precedence: request.precedence,
9422                            depth: request.depth.saturating_add(1),
9423                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9424                            recovery_state: request.recovery_state,
9425                        },
9426                        FastRecognizeScratch {
9427                            predicate_context,
9428                            visiting: &mut *visiting,
9429                            memo: &mut *memo,
9430                            expected: &mut *expected,
9431                            native_depth: native_depth + 1,
9432                        },
9433                    );
9434                    for mut outcome in suffixes {
9435                        outcome.deferred_nodes = self
9436                            .recognition_arena
9437                            .concat_deferred_nodes(path_nodes, outcome.deferred_nodes);
9438                        outcome.diagnostics = self
9439                            .recognition_arena
9440                            .concat_diagnostics(path.diagnostics, outcome.diagnostics);
9441                        outcome.consumed_eof |= path.consumed_eof;
9442                        outcomes.push(outcome);
9443                    }
9444                }
9445            }
9446        }
9447        dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
9448        outcomes
9449    }
9450
9451    /// Attempts to reach `stop_state` from `state_number` without committing
9452    /// token consumption to the parser's public stream position.
9453    fn recognize_state_fast(
9454        &mut self,
9455        atn: &Atn,
9456        request: FastRecognizeRequest,
9457        scratch: FastRecognizeScratch<'_, '_>,
9458    ) -> Vec<FastRecognizeOutcome> {
9459        if scratch.native_depth != 0 && scratch.native_depth < FAST_RECOGNIZE_STACK_CHECK_INTERVAL {
9460            return self.recognize_state_fast_inner(atn, request, scratch);
9461        }
9462        self.recognize_state_fast_checked(atn, request, scratch)
9463    }
9464
9465    #[inline(never)]
9466    fn recognize_state_fast_checked(
9467        &mut self,
9468        atn: &Atn,
9469        request: FastRecognizeRequest,
9470        mut scratch: FastRecognizeScratch<'_, '_>,
9471    ) -> Vec<FastRecognizeOutcome> {
9472        scratch.native_depth = 1;
9473        stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, || {
9474            self.recognize_state_fast_inner(atn, request, scratch)
9475        })
9476    }
9477
9478    #[allow(clippy::too_many_lines)]
9479    fn recognize_state_fast_inner(
9480        &mut self,
9481        atn: &Atn,
9482        request: FastRecognizeRequest,
9483        scratch: FastRecognizeScratch<'_, '_>,
9484    ) -> Vec<FastRecognizeOutcome> {
9485        #[cfg(feature = "perf-counters")]
9486        perf_counters::inc(&perf_counters::RFS_CALLS, 1);
9487        let FastRecognizeScratch {
9488            predicate_context,
9489            visiting,
9490            memo,
9491            expected,
9492            native_depth,
9493        } = scratch;
9494        let FastRecognizeRequest {
9495            mut state_number,
9496            stop_state,
9497            mut index,
9498            rule_start_index,
9499            decision_start_index,
9500            precedence,
9501            mut depth,
9502            recovery_symbols,
9503            recovery_state,
9504        } = request;
9505        let max_token_type = atn.max_token_type();
9506        // Walk straight-line epsilon chains in a loop instead of recursing
9507        // into `recognize_state_fast` for each intermediate state. ATN
9508        // serialization places long sequences of `BasicBlock` epsilon
9509        // transitions between decisions: turning that chain into a loop
9510        // collapses many recursive calls (and their memo lookups, vec
9511        // allocations, and visit-set churn) into a single function frame.
9512        // The loop exits as soon as we hit the original state's logic
9513        // (multi-alt, decision, rule call, unmatched atom/range/set, gated
9514        // precedence) so existing fanout, recovery, and memoization still
9515        // apply unchanged.
9516        //
9517        // The inline case also handles single-atom-match states on the
9518        // happy-pass path: when the lone consuming transition matches the
9519        // current lookahead, advance the index and continue without paying
9520        // for a full `recognize_state_fast` recursion. We track tokens we
9521        // consumed inline in `inline_consumed_tokens` so they can be
9522        // prepended onto the eventual outcome list once we hit a state
9523        // whose handling falls outside this fast loop.
9524        let mut inline_consumed_tokens: Vec<usize> = Vec::new();
9525        let mut inline_consumed_eof = false;
9526        loop {
9527            if depth > RECOGNITION_DEPTH_LIMIT {
9528                return Vec::new();
9529            }
9530            if state_number == stop_state {
9531                let mut nodes = NodeSeqId::EMPTY;
9532                if self.fast_token_nodes_enabled {
9533                    for token_index in inline_consumed_tokens.iter().rev() {
9534                        let token = self.arena_token_node(*token_index, false);
9535                        self.arena_prepend(&mut nodes, token);
9536                    }
9537                }
9538                return vec![FastRecognizeOutcome {
9539                    index,
9540                    consumed_eof: inline_consumed_eof,
9541                    diagnostics: DiagnosticSeqId::EMPTY,
9542                    deferred_nodes: FastDeferredNodeId::EMPTY,
9543                    nodes,
9544                }];
9545            }
9546            let Some(state) = atn.state(state_number) else {
9547                return Vec::new();
9548            };
9549            let transitions = state.transitions();
9550            if transitions.len() == 1 && !state.precedence_rule_decision() {
9551                let transition = transitions
9552                    .first()
9553                    .expect("single transition checked above");
9554                let transition_kind = transition.kind();
9555                let target = transition.target();
9556                match transition_kind {
9557                    ParserTransitionKind::Epsilon | ParserTransitionKind::Action
9558                        if left_recursive_boundary(atn, state, target).is_none() =>
9559                    {
9560                        #[cfg(feature = "perf-counters")]
9561                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9562                        state_number = target;
9563                        depth += 1;
9564                        continue;
9565                    }
9566                    ParserTransitionKind::Predicate
9567                        if left_recursive_boundary(atn, state, target).is_none() =>
9568                    {
9569                        #[cfg(feature = "perf-counters")]
9570                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9571                        if !self.fast_parser_predicate_matches(predicate_context, transition, index)
9572                        {
9573                            record_predicate_no_viable(expected, decision_start_index, index);
9574                            return Vec::new();
9575                        }
9576                        state_number = target;
9577                        depth += 1;
9578                        continue;
9579                    }
9580                    ParserTransitionKind::Precedence
9581                        if packed_i32(transition.arg0()) >= precedence
9582                            && left_recursive_boundary(atn, state, target).is_none() =>
9583                    {
9584                        #[cfg(feature = "perf-counters")]
9585                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9586                        state_number = target;
9587                        depth += 1;
9588                        continue;
9589                    }
9590                    // Single-atom / range / set / wildcard / not-set states
9591                    // are common (~17K of ~125K calls on C#) and almost
9592                    // always succeed in pass 1: no fanout, no recovery, no
9593                    // diagnostics. Inline the token match and continue
9594                    // walking instead of recursing — the recursive path
9595                    // would just allocate a Vec, build one outcome, prepend
9596                    // a Token node, and return. Skip pass 2 (recovery
9597                    // enabled): there the failure branch matters and the
9598                    // existing recursive code records expected symbols.
9599                    ParserTransitionKind::Atom
9600                    | ParserTransitionKind::Range
9601                    | ParserTransitionKind::Set
9602                    | ParserTransitionKind::NotSet
9603                    | ParserTransitionKind::Wildcard
9604                        if !self.fast_recovery_enabled =>
9605                    {
9606                        let symbol = self.token_type_at(index);
9607                        if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
9608                            #[cfg(feature = "perf-counters")]
9609                            perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
9610                            if self.fast_token_nodes_enabled {
9611                                inline_consumed_tokens.push(index);
9612                            }
9613                            inline_consumed_eof |= symbol == TOKEN_EOF;
9614                            index = self.consume_index(index, symbol);
9615                            state_number = target;
9616                            depth += 1;
9617                            continue;
9618                        }
9619                        // Fall through to break and let the regular
9620                        // body handle the no-match case (returns empty).
9621                    }
9622                    _ => {}
9623                }
9624            }
9625            break;
9626        }
9627        // If we collected token nodes inline but bail to the recursive
9628        // body (decision state, rule call, etc.), the outcomes returned
9629        // below will need those token nodes prepended.
9630        let inline_pending = !inline_consumed_tokens.is_empty() || inline_consumed_eof;
9631        let Some(state) = atn.state(state_number) else {
9632            return Vec::new();
9633        };
9634        let transitions = state.transitions();
9635        let transition_count = transitions.len();
9636        if !self.fast_recovery_enabled
9637            && let Some(shape) = fast_repetition_shape(atn, state)
9638        {
9639            let mut outcomes = self.recognize_repetition_fast(
9640                atn,
9641                &FastRecognizeRequest {
9642                    state_number,
9643                    stop_state,
9644                    index,
9645                    rule_start_index,
9646                    decision_start_index,
9647                    precedence,
9648                    depth,
9649                    recovery_symbols: Rc::clone(&recovery_symbols),
9650                    recovery_state,
9651                },
9652                shape,
9653                FastRecognizeScratch {
9654                    predicate_context,
9655                    visiting: &mut *visiting,
9656                    memo: &mut *memo,
9657                    expected: &mut *expected,
9658                    native_depth: native_depth + 1,
9659                },
9660            );
9661            if inline_pending {
9662                for outcome in &mut outcomes {
9663                    outcome.consumed_eof |= inline_consumed_eof;
9664                    if self.fast_token_nodes_enabled {
9665                        for token_index in inline_consumed_tokens.iter().rev() {
9666                            let token = self.arena_token_node(*token_index, false);
9667                            self.defer_fast_outcome_node(outcome, token);
9668                        }
9669                    }
9670                }
9671            }
9672            return outcomes;
9673        }
9674        // In pass 1 (`fast_recovery_enabled == false`) the recovery-related
9675        // fields and the rule/decision boundary indices are pure plumbing —
9676        // they only affect the recovery branch and the no-viable diagnostic
9677        // recording, neither of which fires when recovery is off. Zeroing
9678        // them in the memo key collapses calls that visit the same
9679        // `(state, index)` from different rule-call sites onto one cache
9680        // entry, which is the dominant cost on large grammars (e.g. C#) where
9681        // many rules eventually delegate into the same `expression` /
9682        // `primary_expression` / `type` branches.
9683        let key = if self.fast_recovery_enabled {
9684            FastRecognizeKey {
9685                state_number,
9686                stop_state,
9687                index,
9688                rule_start_index,
9689                decision_start_index,
9690                precedence,
9691                recovery_symbols_id: Rc::as_ptr(&recovery_symbols) as usize,
9692                recovery_state,
9693            }
9694        } else {
9695            FastRecognizeKey {
9696                state_number,
9697                stop_state,
9698                index,
9699                rule_start_index: 0,
9700                decision_start_index: None,
9701                precedence,
9702                recovery_symbols_id: 0,
9703                recovery_state: None,
9704            }
9705        };
9706        // Once the clean-pass probe has established that coordinates do not
9707        // repeat, stop paying for the full memo table. Recovery always keeps
9708        // memoization because cached failures carry diagnostics, while
9709        // repeat-heavy clean parses promote before reaching sparse mode.
9710        let memo_lookup_enabled = self.fast_recovery_enabled
9711            || (transition_count > 1 && self.clean_memo_enabled_for_key(&key));
9712        if memo_lookup_enabled {
9713            if let Some(outcomes) = memo.get(&key) {
9714                #[cfg(feature = "perf-counters")]
9715                {
9716                    perf_counters::inc(&perf_counters::RFS_MEMO_HITS, 1);
9717                    perf_counters::inc(&perf_counters::OUTCOMES_CLONED, outcomes.len() as u64);
9718                }
9719                // Materialize a fresh `Vec` from the cached slice; the caller
9720                // mutates per-outcome state (eof flags, prepended nodes) so we
9721                // can't hand them the shared backing.
9722                if !inline_consumed_tokens.is_empty() || inline_consumed_eof {
9723                    let inline_eof = inline_consumed_eof;
9724                    let inline_tokens = &inline_consumed_tokens;
9725                    return outcomes
9726                        .iter()
9727                        .copied()
9728                        .map(|mut outcome| {
9729                            if inline_eof {
9730                                outcome.consumed_eof = true;
9731                            }
9732                            if self.fast_token_nodes_enabled {
9733                                for token_index in inline_tokens.iter().rev() {
9734                                    let token = self.arena_token_node(*token_index, false);
9735                                    self.defer_fast_outcome_node(&mut outcome, token);
9736                                }
9737                            }
9738                            outcome
9739                        })
9740                        .collect();
9741                }
9742                return outcomes.to_vec();
9743            }
9744            #[cfg(feature = "perf-counters")]
9745            perf_counters::inc(&perf_counters::RFS_MEMO_MISSES, 1);
9746        }
9747
9748        // Cycle detection: clean recognition keeps the narrow static cycle
9749        // guard used on hot paths. Recovery needs the broader epsilon-state
9750        // guard because an otherwise non-nullable loop body can recover as an
9751        // empty child at EOF and re-enter the loop at the same token.
9752        let needs_cycle_guard = if self.fast_recovery_enabled {
9753            transitions.iter().any(ParserTransition::is_epsilon)
9754        } else {
9755            transition_count > 1 && self.state_can_reenter_without_consuming(atn, state_number)
9756        };
9757        #[cfg(feature = "perf-counters")]
9758        if needs_cycle_guard {
9759            perf_counters::inc(&perf_counters::MULTI_TRANS_BODY, 1);
9760        } else {
9761            perf_counters::inc(&perf_counters::SINGLE_TRANS_BODY, 1);
9762            match state
9763                .transitions()
9764                .first()
9765                .expect("single-transition path requires one transition")
9766                .data()
9767            {
9768                Transition::Rule { .. } => {
9769                    perf_counters::inc(&perf_counters::SINGLE_TRANS_RULE, 1);
9770                }
9771                Transition::Atom { .. }
9772                | Transition::Range { .. }
9773                | Transition::Set { .. }
9774                | Transition::NotSet { .. }
9775                | Transition::Wildcard { .. } => {
9776                    perf_counters::inc(&perf_counters::SINGLE_TRANS_ATOM, 1);
9777                }
9778                _ => {
9779                    perf_counters::inc(&perf_counters::SINGLE_TRANS_OTHER, 1);
9780                }
9781            }
9782        }
9783        let has_inserted_cycle_guard = if needs_cycle_guard {
9784            if !visiting.insert(key.clone()) {
9785                #[cfg(feature = "perf-counters")]
9786                perf_counters::inc(&perf_counters::RFS_VISITING_CYCLE, 1);
9787                return Vec::new();
9788            }
9789            true
9790        } else {
9791            false
9792        };
9793        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
9794            Some(index)
9795        } else {
9796            decision_start_index
9797        };
9798        let (epsilon_recovery_symbols, epsilon_recovery_state) = if self.fast_recovery_enabled {
9799            fast_next_recovery_context(self, atn, state, &recovery_symbols, recovery_state)
9800        } else {
9801            (Rc::clone(&recovery_symbols), recovery_state)
9802        };
9803
9804        // Lookahead-based pruning. At a multi-alternative state we cache the
9805        // look-1 set of every outgoing transition; on visit we keep only the
9806        // transitions whose look-1 can accept the current lookahead (or that
9807        // can be reached without consuming and so could legitimately match a
9808        // shorter input). This is the main speedup vs. blind speculative
9809        // recursion: it lets each visit fan out only to the alternatives that
9810        // could possibly contribute a clean parse, mirroring the SLL phase of
9811        // ANTLR's adaptive prediction.
9812        //
9813        // Pruning is skipped at:
9814        //   * rule-start states (a child rule call may need every internal
9815        //     transition to surface single-token recovery diagnostics that
9816        //     ANTLR's reference parser emits at the rule's first consuming
9817        //     transition; the FIRST-set retry path turns the prefilter off
9818        //     entirely so let's keep this lightweight too),
9819        //   * left-recursive precedence loops (the precedence transition's
9820        //     gating is dynamic),
9821        //   * states with too few alternatives to benefit.
9822        let lookahead_filter = if transition_count > 1
9823            && self.fast_first_set_prefilter
9824            && !state.precedence_rule_decision()
9825            && (!self.fast_recovery_enabled || state.kind() != AtnStateKind::RuleStart)
9826        {
9827            state
9828                .rule_index()
9829                .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9830                .map(|rule_stop| {
9831                    let symbol = self.token_type_at(index);
9832                    let entry = self.cached_decision_lookahead(atn, state, rule_stop);
9833                    (symbol, entry)
9834                })
9835        } else {
9836            None
9837        };
9838        // LL(1) fast path: when the FIRST sets for the decision are disjoint
9839        // and none is nullable, the lookahead deterministically selects one
9840        // alternative. The recursive recognizer can then commit to that single
9841        // alt without iterating every transition through `should_skip_via_lookahead`
9842        // — saving (transition_count - 1) filter probes per visit.
9843        //
9844        // Result is cached per `(state, lookahead_token)` on the parser
9845        // instance, so subsequent visits skip the FIRST-set scan entirely.
9846        let ll1_only_alt: Option<usize> = if transition_count > 1
9847            && let Some((symbol, entry)) = lookahead_filter.as_ref()
9848        {
9849            let key = (state.state_number(), *symbol);
9850            if let Some(&cached) = self.ll1_decision_cache.get(&key) {
9851                cached
9852            } else {
9853                let result = ll1_unique_alt(entry, *symbol);
9854                self.ll1_decision_cache.insert(key, result);
9855                result
9856            }
9857        } else {
9858            None
9859        };
9860        let lookahead_filter = lookahead_filter.as_ref();
9861        // Pre-size only when we expect at least one outcome to land — most
9862        // single-transition fall-throughs (the loop above didn't catch
9863        // because they're atom/rule/predicate) push at most one entry, so
9864        // reserving one slot avoids a reallocation while keeping the
9865        // unused-slot waste at one element.
9866        let mut outcomes: Vec<FastRecognizeOutcome> = Vec::with_capacity(transition_count.min(2));
9867        for (transition_index, transition) in transitions.iter().enumerate() {
9868            if let Some(alt) = ll1_only_alt {
9869                // LL(1) determinism: skip every alt except the chosen one.
9870                if alt != transition_index {
9871                    continue;
9872                }
9873            }
9874            let transition_kind = transition.kind();
9875            if ll1_only_alt.is_none()
9876                && should_skip_via_lookahead(
9877                    transition_kind,
9878                    transition_index,
9879                    lookahead_filter,
9880                    index,
9881                    self.fast_recovery_enabled,
9882                    expected,
9883                )
9884            {
9885                continue;
9886            }
9887            let target = transition.target();
9888            let outcomes_before_transition = outcomes.len();
9889            let left_recursive_boundary = match transition_kind {
9890                ParserTransitionKind::Epsilon
9891                | ParserTransitionKind::Action
9892                | ParserTransitionKind::Predicate
9893                | ParserTransitionKind::Precedence => left_recursive_boundary(atn, state, target),
9894                ParserTransitionKind::Atom
9895                | ParserTransitionKind::Range
9896                | ParserTransitionKind::Set
9897                | ParserTransitionKind::NotSet
9898                | ParserTransitionKind::Wildcard
9899                | ParserTransitionKind::Rule => None,
9900            };
9901            match transition_kind {
9902                ParserTransitionKind::Epsilon | ParserTransitionKind::Action => {
9903                    #[cfg(feature = "perf-counters")]
9904                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9905                    outcomes.extend(self.recognize_state_fast(
9906                        atn,
9907                        FastRecognizeRequest {
9908                            state_number: target,
9909                            stop_state,
9910                            index,
9911                            rule_start_index,
9912                            decision_start_index: next_decision_start_index,
9913                            precedence,
9914                            depth: depth + 1,
9915                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9916                            recovery_state: epsilon_recovery_state,
9917                        },
9918                        FastRecognizeScratch {
9919                            predicate_context,
9920                            visiting,
9921                            memo,
9922                            expected,
9923                            native_depth: native_depth + 1,
9924                        },
9925                    ));
9926                }
9927                ParserTransitionKind::Predicate => {
9928                    #[cfg(feature = "perf-counters")]
9929                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9930                    if self.fast_parser_predicate_matches(predicate_context, transition, index) {
9931                        outcomes.extend(self.recognize_state_fast(
9932                            atn,
9933                            FastRecognizeRequest {
9934                                state_number: target,
9935                                stop_state,
9936                                index,
9937                                rule_start_index,
9938                                decision_start_index: next_decision_start_index,
9939                                precedence,
9940                                depth: depth + 1,
9941                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9942                                recovery_state: epsilon_recovery_state,
9943                            },
9944                            FastRecognizeScratch {
9945                                predicate_context,
9946                                visiting,
9947                                memo,
9948                                expected,
9949                                native_depth: native_depth + 1,
9950                            },
9951                        ));
9952                    } else {
9953                        record_predicate_no_viable(expected, next_decision_start_index, index);
9954                    }
9955                }
9956                ParserTransitionKind::Precedence => {
9957                    let transition_precedence = packed_i32(transition.arg0());
9958                    if transition_precedence >= precedence {
9959                        outcomes.extend(self.recognize_state_fast(
9960                            atn,
9961                            FastRecognizeRequest {
9962                                state_number: target,
9963                                stop_state,
9964                                index,
9965                                rule_start_index,
9966                                decision_start_index: next_decision_start_index,
9967                                precedence,
9968                                depth: depth + 1,
9969                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9970                                recovery_state: epsilon_recovery_state,
9971                            },
9972                            FastRecognizeScratch {
9973                                predicate_context,
9974                                visiting,
9975                                memo,
9976                                expected,
9977                                native_depth: native_depth + 1,
9978                            },
9979                        ));
9980                    }
9981                }
9982                ParserTransitionKind::Rule => {
9983                    let rule_index = transition.arg0() as usize;
9984                    let follow_state = transition.arg1() as usize;
9985                    let rule_precedence = packed_i32(transition.arg2());
9986                    #[cfg(feature = "perf-counters")]
9987                    perf_counters::inc(&perf_counters::RULE_TRANSITIONS, 1);
9988                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
9989                        continue;
9990                    };
9991                    // Lookahead-based pruning. The recognizer would otherwise
9992                    // explore every speculative rule call, producing exponential
9993                    // work on grammars with many epsilon-reachable rules. When
9994                    // the rule is non-nullable and its FIRST set excludes the
9995                    // current lookahead, recursion can't find a clean path
9996                    // *through this rule*. Skipping is only safe if some sibling
9997                    // transition can still consume the lookahead — otherwise the
9998                    // rule call is the sole continuation and must run so the
9999                    // single-token insertion / deletion recovery inside the
10000                    // called rule can fire (mirroring ANTLR's reference behavior
10001                    // of conjuring a missing token at child-rule entry).
10002                    let symbol = self.token_type_at(index);
10003                    if self.fast_first_set_prefilter {
10004                        // Probe the shared cross-parse cache first; build
10005                        // the entry on miss and intern it there. The
10006                        // computation is purely a function of the ATN, so
10007                        // the cached entry is reused across parses (and
10008                        // freshly-instantiated parser values that share
10009                        // the same `&'static Atn`).
10010                        //
10011                        // `rule_first_set` returns the computed entry
10012                        // directly — it intentionally skips inserting into
10013                        // the cache when the FIRST-set walk hit a cycle, so
10014                        // we cannot assume the entry is in the cache after
10015                        // computing it.
10016                        let first = self.cached_rule_first_set(atn, target, child_stop);
10017                        if should_skip_rule_via_first_set(
10018                            &first,
10019                            symbol,
10020                            self.fast_recovery_enabled,
10021                            index,
10022                            expected,
10023                        ) {
10024                            continue;
10025                        }
10026                    }
10027                    let expected_before_child =
10028                        self.fast_recovery_enabled.then(|| expected.clone());
10029                    let mut children = self.recognize_state_fast(
10030                        atn,
10031                        FastRecognizeRequest {
10032                            state_number: target,
10033                            stop_state: child_stop,
10034                            index,
10035                            rule_start_index: index,
10036                            decision_start_index: None,
10037                            precedence: rule_precedence,
10038                            depth: depth + 1,
10039                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
10040                            recovery_state: epsilon_recovery_state,
10041                        },
10042                        FastRecognizeScratch {
10043                            predicate_context,
10044                            visiting,
10045                            memo,
10046                            expected,
10047                            native_depth: native_depth + 1,
10048                        },
10049                    );
10050                    if children.is_empty() && self.fast_recovery_enabled {
10051                        children = self.fast_child_rule_failure_recovery_outcomes(
10052                            FastChildRuleFailureRecoveryRequest {
10053                                atn,
10054                                rule_index,
10055                                start_index: index,
10056                                follow_state,
10057                                stop_state,
10058                                expected,
10059                            },
10060                        );
10061                    }
10062                    if let Some(expected_before_child) = expected_before_child {
10063                        if children
10064                            .iter()
10065                            .any(|child| child.diagnostics.is_empty() && child.index > index)
10066                        {
10067                            *expected = expected_before_child;
10068                        }
10069                    }
10070                    for child in children {
10071                        let child_index = child.index;
10072                        let child_consumed_eof = child.consumed_eof;
10073                        let child_diagnostics = child.diagnostics;
10074                        let empty_recovery = self.empty_recovery_symbols();
10075                        let follow_outcomes = self.recognize_state_fast(
10076                            atn,
10077                            FastRecognizeRequest {
10078                                state_number: follow_state,
10079                                stop_state,
10080                                index: child_index,
10081                                rule_start_index,
10082                                decision_start_index: next_decision_start_index,
10083                                precedence,
10084                                depth: depth + 1,
10085                                recovery_symbols: empty_recovery,
10086                                recovery_state: None,
10087                            },
10088                            FastRecognizeScratch {
10089                                predicate_context,
10090                                visiting,
10091                                memo,
10092                                expected,
10093                                native_depth: native_depth + 1,
10094                            },
10095                        );
10096                        if follow_outcomes.is_empty() {
10097                            continue;
10098                        }
10099                        let child_stop_index =
10100                            self.rule_stop_token_index(child_index, child_consumed_eof);
10101                        let child_node = self.build_parse_trees.then(|| {
10102                            self.recognition_arena.deferred_rule_node(FastDeferredRule {
10103                                rule_index: u32::try_from(rule_index)
10104                                    .expect("rule index fits in u32"),
10105                                invoking_state: i32::try_from(invoking_state_number(state_number))
10106                                    .expect("invoking state fits in i32"),
10107                                start_index: u32::try_from(index)
10108                                    .expect("rule start index fits in u32"),
10109                                stop_index: child_stop_index.map(|stop_index| {
10110                                    u32::try_from(stop_index).expect("rule stop index fits in u32")
10111                                }),
10112                                deferred_children: child.deferred_nodes,
10113                                children: child.nodes,
10114                            })
10115                        });
10116                        let child_diags_empty = child_diagnostics.is_empty();
10117                        outcomes.extend(follow_outcomes.into_iter().map(|mut outcome| {
10118                            outcome.consumed_eof |= child_consumed_eof;
10119                            // Skip the prepend dance when there's nothing to
10120                            // merge from the child — common case in pass 1.
10121                            if !child_diags_empty {
10122                                outcome.diagnostics = self
10123                                    .recognition_arena
10124                                    .concat_diagnostics(child_diagnostics, outcome.diagnostics);
10125                            }
10126                            if let Some(child_node) = child_node {
10127                                outcome.deferred_nodes = self
10128                                    .recognition_arena
10129                                    .concat_deferred_nodes(child_node, outcome.deferred_nodes);
10130                            }
10131                            outcome
10132                        }));
10133                    }
10134                }
10135                ParserTransitionKind::Atom
10136                | ParserTransitionKind::Range
10137                | ParserTransitionKind::Set
10138                | ParserTransitionKind::NotSet
10139                | ParserTransitionKind::Wildcard => {
10140                    #[cfg(feature = "perf-counters")]
10141                    perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
10142                    let symbol = self.token_type_at(index);
10143                    if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
10144                        let next_index = self.consume_index(index, symbol);
10145                        let empty_recovery = self.empty_recovery_symbols();
10146                        outcomes.extend(
10147                            self.recognize_state_fast(
10148                                atn,
10149                                FastRecognizeRequest {
10150                                    state_number: target,
10151                                    stop_state,
10152                                    index: next_index,
10153                                    rule_start_index,
10154                                    decision_start_index: next_decision_start_index,
10155                                    precedence,
10156                                    depth: depth + 1,
10157                                    recovery_symbols: empty_recovery,
10158                                    recovery_state: None,
10159                                },
10160                                FastRecognizeScratch {
10161                                    predicate_context,
10162                                    visiting,
10163                                    memo,
10164                                    expected,
10165                                    native_depth: native_depth + 1,
10166                                },
10167                            )
10168                            .into_iter()
10169                            .map(|mut outcome| {
10170                                outcome.consumed_eof |= symbol == TOKEN_EOF;
10171                                if self.fast_token_nodes_enabled {
10172                                    let token = self.arena_token_node(index, false);
10173                                    self.defer_fast_outcome_node(&mut outcome, token);
10174                                }
10175                                outcome
10176                            }),
10177                        );
10178                    } else {
10179                        if !self.fast_recovery_enabled {
10180                            // In pass 1 there is no recovery to attempt; the
10181                            // recovery branch below would never run, and the
10182                            // `expected_symbols` computation is just there
10183                            // to gate that branch. Skipping it eliminates
10184                            // ~1× `state_expected_symbols` lookup per failed
10185                            // atom transition (≈82K on mono-statement.cs)
10186                            // for zero observable behavior change.
10187                            continue;
10188                        }
10189                        let expected_symbols = fast_recovery_expected_symbols(
10190                            self,
10191                            atn,
10192                            state.state_number(),
10193                            &recovery_symbols,
10194                        );
10195                        if expected_symbols.contains(&symbol) {
10196                            continue;
10197                        }
10198                        {
10199                            expected.record_transition(index, transition, max_token_type);
10200                            record_no_viable_if_ambiguous(
10201                                expected,
10202                                next_decision_start_index,
10203                                index,
10204                            );
10205                            outcomes.extend(self.fast_single_token_deletion_recovery(
10206                                FastRecoveryRequest {
10207                                    atn,
10208                                    transition,
10209                                    expected_symbols: Rc::clone(&expected_symbols),
10210                                    target,
10211                                    request: FastRecognizeRequest {
10212                                        state_number,
10213                                        stop_state,
10214                                        index,
10215                                        rule_start_index,
10216                                        decision_start_index,
10217                                        precedence,
10218                                        depth,
10219                                        recovery_symbols: Rc::clone(&recovery_symbols),
10220                                        recovery_state,
10221                                    },
10222                                    visiting,
10223                                    memo,
10224                                    expected,
10225                                },
10226                                predicate_context,
10227                            ));
10228                            if !state_is_left_recursive_rule(atn, state) {
10229                                outcomes.extend(self.fast_single_token_insertion_recovery(
10230                                    FastRecoveryRequest {
10231                                        atn,
10232                                        transition,
10233                                        expected_symbols: Rc::clone(&expected_symbols),
10234                                        target,
10235                                        request: FastRecognizeRequest {
10236                                            state_number,
10237                                            stop_state,
10238                                            index,
10239                                            rule_start_index,
10240                                            decision_start_index,
10241                                            precedence,
10242                                            depth,
10243                                            recovery_symbols: Rc::clone(&recovery_symbols),
10244                                            recovery_state,
10245                                        },
10246                                        visiting,
10247                                        memo,
10248                                        expected,
10249                                    },
10250                                    predicate_context,
10251                                ));
10252                            }
10253                            outcomes.extend(self.fast_current_token_deletion_recovery(
10254                                FastCurrentTokenDeletionRequest {
10255                                    atn,
10256                                    expected_symbols,
10257                                    request: FastRecognizeRequest {
10258                                        state_number,
10259                                        stop_state,
10260                                        index,
10261                                        rule_start_index,
10262                                        decision_start_index,
10263                                        precedence,
10264                                        depth,
10265                                        recovery_symbols: Rc::clone(&recovery_symbols),
10266                                        recovery_state,
10267                                    },
10268                                    visiting,
10269                                    memo,
10270                                    expected,
10271                                },
10272                                predicate_context,
10273                            ));
10274                        }
10275                    }
10276                }
10277            }
10278            let alt_number = next_alt_number(
10279                state,
10280                transition_count,
10281                transition_index,
10282                0,
10283                self.fast_track_alt_numbers,
10284            );
10285            if alt_number != 0 || left_recursive_boundary.is_some() {
10286                for outcome in &mut outcomes[outcomes_before_transition..] {
10287                    if alt_number != 0 {
10288                        self.defer_fast_outcome_alternative(outcome, alt_number);
10289                    }
10290                    if let Some(rule_index) = left_recursive_boundary {
10291                        self.defer_fast_outcome_boundary(outcome, rule_index);
10292                    }
10293                }
10294            }
10295        }
10296
10297        if has_inserted_cycle_guard {
10298            visiting.remove(&key);
10299        }
10300        if matches!(
10301            self.prediction_mode,
10302            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
10303        ) && self.fast_recovery_enabled
10304        {
10305            // Without recovery enabled every outcome already has empty
10306            // diagnostics, so the discard pass is a no-op — skipping it
10307            // saves an iter+retain on each of the ~1M visits.
10308            discard_recovered_fast_outcomes_if_clean_path_exists(&mut outcomes);
10309        }
10310        if self.fast_recovery_enabled {
10311            dedupe_fast_outcomes(&mut outcomes, &self.recognition_arena);
10312        } else {
10313            dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
10314        }
10315        // Skip memoization for single-transition states whose outcome is
10316        // unambiguous: they only get re-entered if the caller revisits the
10317        // exact same call site, which is rare since the loop above already
10318        // collapsed straight-line epsilon walks. Multi-alternative states
10319        // are where backtracking actually revisits the same coordinate, so
10320        // we still memoize there. With recovery on we keep the existing
10321        // memoization unconditionally because the recovery branch may
10322        // record diagnostics that the cache must surface to repeated
10323        // failed visits.
10324        let should_memoize = self.fast_recovery_enabled
10325            || (transition_count > 1 && self.clean_memo_mode != CleanMemoMode::Sparse);
10326        // Apply inline pending state to each outcome before returning.
10327        // Tokens consumed inline by the loop-collapse don't appear in the
10328        // recursive recognizer's output, so we need to prepend them here.
10329        let mut apply_inline_pending = |mut outcome: FastRecognizeOutcome| -> FastRecognizeOutcome {
10330            if inline_consumed_eof {
10331                outcome.consumed_eof = true;
10332            }
10333            if !inline_consumed_tokens.is_empty() {
10334                for token_index in inline_consumed_tokens.iter().rev() {
10335                    let token = self.arena_token_node(*token_index, false);
10336                    self.defer_fast_outcome_node(&mut outcome, token);
10337                }
10338            }
10339            outcome
10340        };
10341        if should_memoize {
10342            #[cfg(feature = "perf-counters")]
10343            {
10344                perf_counters::inc(&perf_counters::MEMO_INSERTED, 1);
10345                perf_counters::inc(&perf_counters::OUTCOMES_PUSHED, outcomes.len() as u64);
10346                match outcomes.len() {
10347                    0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10348                    1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10349                    _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10350                }
10351            }
10352            // The memo is keyed by the loop-exit `(state_number, index)` so
10353            // the inline-consumed tokens belong to *this* call's output, not
10354            // the cached result. Memoize the bare outcomes (without the
10355            // inline-pending data), then prepend the inline data on return.
10356            let stored: Rc<[FastRecognizeOutcome]> = Rc::from(outcomes);
10357            memo.insert(key, Rc::clone(&stored));
10358            if inline_pending {
10359                return stored
10360                    .iter()
10361                    .copied()
10362                    .map(&mut apply_inline_pending)
10363                    .collect();
10364            }
10365            return stored.to_vec();
10366        }
10367        #[cfg(feature = "perf-counters")]
10368        match outcomes.len() {
10369            0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10370            1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10371            _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10372        }
10373        if inline_pending {
10374            return outcomes.into_iter().map(apply_inline_pending).collect();
10375        }
10376        outcomes
10377    }
10378
10379    /// Explores single-token deletion recovery while preserving the matched
10380    /// token and skipped error token in the selected parse tree path.
10381    fn single_token_deletion_recovery(
10382        &mut self,
10383        recovery: RecoveryRequest<'_, '_>,
10384    ) -> Vec<RecognizeOutcome> {
10385        let RecoveryRequest {
10386            atn,
10387            transition,
10388            expected_symbols,
10389            target,
10390            request,
10391            visiting,
10392            memo,
10393            expected,
10394        } = recovery;
10395        let RecognizeRequest {
10396            stop_state,
10397            index,
10398            rule_start_index,
10399            decision_start_index,
10400            init_action_rules,
10401            predicates,
10402            semantics,
10403            rule_args,
10404            member_actions,
10405            return_actions,
10406            local_int_arg,
10407            member_values,
10408            return_values,
10409            rule_alt_number,
10410            track_alt_numbers,
10411            consumed_eof,
10412            precedence,
10413            depth,
10414            ..
10415        } = request;
10416        let Some((diagnostic, next_index, next_symbol)) =
10417            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
10418        else {
10419            return Vec::new();
10420        };
10421        let after_next = self.consume_index(next_index, next_symbol);
10422        self.recognize_state(
10423            atn,
10424            RecognizeRequest {
10425                state_number: target,
10426                stop_state,
10427                index: after_next,
10428                rule_start_index,
10429                decision_start_index,
10430                init_action_rules,
10431                predicates,
10432                semantics,
10433                rule_args,
10434                member_actions,
10435                return_actions,
10436                local_int_arg,
10437                member_values,
10438                return_values,
10439                rule_alt_number,
10440                track_alt_numbers,
10441                consumed_eof: consumed_eof || next_symbol == TOKEN_EOF,
10442                committed_decision: false,
10443                precedence,
10444                depth: depth + 1,
10445                recovery_symbols: BTreeSet::new(),
10446                recovery_state: None,
10447            },
10448            visiting,
10449            memo,
10450            expected,
10451        )
10452        .into_iter()
10453        .map(|mut outcome| {
10454            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
10455            outcome.diagnostics = self
10456                .recognition_arena
10457                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10458            let token = self.arena_token_node(next_index, false);
10459            self.arena_prepend(&mut outcome.nodes, token);
10460            let error = self.arena_token_node(index, true);
10461            self.arena_prepend(&mut outcome.nodes, error);
10462            outcome
10463        })
10464        .collect()
10465    }
10466
10467    /// Retries the current recognition state after deleting one unexpected
10468    /// token, preserving the deleted token as an error node in the parse tree.
10469    fn current_token_deletion_recovery(
10470        &mut self,
10471        recovery: CurrentTokenDeletionRequest<'_, '_>,
10472    ) -> Vec<RecognizeOutcome> {
10473        let CurrentTokenDeletionRequest {
10474            atn,
10475            expected_symbols,
10476            mut request,
10477            visiting,
10478            memo,
10479            expected,
10480        } = recovery;
10481        let error_index = request.index;
10482        if error_index == request.rule_start_index {
10483            return Vec::new();
10484        }
10485        let Some((diagnostic, next_index, skipped)) =
10486            self.current_token_deletion(error_index, &expected_symbols)
10487        else {
10488            return Vec::new();
10489        };
10490        request.state_number = request.recovery_state.unwrap_or(request.state_number);
10491        request.index = next_index;
10492        request.committed_decision = false;
10493        request.depth += 1;
10494        request.recovery_state = None;
10495        self.recognize_state(atn, request, visiting, memo, expected)
10496            .into_iter()
10497            .map(|mut outcome| {
10498                outcome.diagnostics = self
10499                    .recognition_arena
10500                    .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10501                for index in skipped.iter().rev() {
10502                    let error = self.arena_token_node(*index, true);
10503                    self.arena_prepend(&mut outcome.nodes, error);
10504                }
10505                outcome
10506            })
10507            .collect()
10508    }
10509
10510    /// Falls back after deletion/insertion repairs cannot continue from a
10511    /// failed consuming transition.
10512    fn consuming_failure_fallback(
10513        &mut self,
10514        fallback: ConsumingFailureFallback<'_>,
10515        visiting: &mut BTreeSet<RecognizeKey>,
10516        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10517        expected: &mut ExpectedTokens,
10518    ) -> Vec<RecognizeOutcome> {
10519        if fallback.expected_symbols.is_empty() {
10520            return Vec::new();
10521        }
10522        if fallback.symbol == TOKEN_EOF {
10523            return self.eof_consuming_failure_fallback(fallback, expected);
10524        }
10525        self.non_eof_consuming_failure_fallback(fallback, visiting, memo, expected)
10526    }
10527
10528    /// Keeps unexpected non-EOF input visible as an error node when no repair
10529    /// path can otherwise reach the transition target.
10530    fn non_eof_consuming_failure_fallback(
10531        &mut self,
10532        fallback: ConsumingFailureFallback<'_>,
10533        visiting: &mut BTreeSet<RecognizeKey>,
10534        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10535        expected: &mut ExpectedTokens,
10536    ) -> Vec<RecognizeOutcome> {
10537        let ConsumingFailureFallback {
10538            atn,
10539            target,
10540            request,
10541            symbol,
10542            expected_symbols,
10543            decision_start_index,
10544            decision,
10545        } = fallback;
10546        let error_index = request.index;
10547        let diagnostic =
10548            self.recovery_failure_diagnostic(error_index, decision_start_index, &expected_symbols);
10549        let next_index = self.consume_index(error_index, symbol);
10550        self.recognize_state(
10551            atn,
10552            RecognizeRequest {
10553                state_number: target,
10554                stop_state: request.stop_state,
10555                index: next_index,
10556                rule_start_index: request.rule_start_index,
10557                decision_start_index,
10558                init_action_rules: request.init_action_rules,
10559                predicates: request.predicates,
10560                semantics: request.semantics,
10561                rule_args: request.rule_args,
10562                member_actions: request.member_actions,
10563                return_actions: request.return_actions,
10564                local_int_arg: request.local_int_arg,
10565                member_values: request.member_values,
10566                return_values: request.return_values,
10567                rule_alt_number: request.rule_alt_number,
10568                track_alt_numbers: request.track_alt_numbers,
10569                consumed_eof: request.consumed_eof,
10570                committed_decision: false,
10571                precedence: request.precedence,
10572                depth: request.depth + 1,
10573                recovery_symbols: BTreeSet::new(),
10574                recovery_state: None,
10575            },
10576            visiting,
10577            memo,
10578            expected,
10579        )
10580        .into_iter()
10581        .map(|mut outcome| {
10582            prepend_decision(&mut outcome, decision);
10583            outcome.diagnostics = self
10584                .recognition_arena
10585                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10586            let error = self.arena_token_node(error_index, true);
10587            self.arena_prepend(&mut outcome.nodes, error);
10588            outcome
10589        })
10590        .collect()
10591    }
10592
10593    /// Stops the current rule at EOF after a nested failure, matching ANTLR's
10594    /// behavior of unwinding instead of inserting caller tokens at EOF.
10595    fn eof_consuming_failure_fallback(
10596        &mut self,
10597        fallback: ConsumingFailureFallback<'_>,
10598        expected: &ExpectedTokens,
10599    ) -> Vec<RecognizeOutcome> {
10600        let request = fallback.request;
10601        if request.index == request.rule_start_index {
10602            return Vec::new();
10603        }
10604        let diagnostic =
10605            self.eof_rule_recovery_diagnostic(request.index, &fallback.expected_symbols, expected);
10606        let diagnostics = self
10607            .recognition_arena
10608            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
10609        vec![RecognizeOutcome {
10610            index: request.index,
10611            consumed_eof: request.consumed_eof,
10612            alt_number: request.rule_alt_number,
10613            member_values: request.member_values,
10614            return_values: request.return_values,
10615            diagnostics,
10616            decisions: Vec::new(),
10617            actions: Vec::new(),
10618            nodes: NodeSeqId::EMPTY,
10619        }]
10620    }
10621
10622    /// Explores single-token insertion recovery while adding a conjured
10623    /// missing-token error node to the selected parse tree path.
10624    fn single_token_insertion_recovery(
10625        &mut self,
10626        recovery: RecoveryRequest<'_, '_>,
10627    ) -> Vec<RecognizeOutcome> {
10628        let RecoveryRequest {
10629            atn,
10630            transition,
10631            expected_symbols,
10632            target,
10633            request,
10634            visiting,
10635            memo,
10636            expected,
10637        } = recovery;
10638        let RecognizeRequest {
10639            stop_state,
10640            index,
10641            rule_start_index,
10642            decision_start_index,
10643            init_action_rules,
10644            predicates,
10645            semantics,
10646            rule_args,
10647            member_actions,
10648            return_actions,
10649            local_int_arg,
10650            member_values,
10651            return_values,
10652            rule_alt_number,
10653            track_alt_numbers,
10654            consumed_eof,
10655            precedence,
10656            depth,
10657            ..
10658        } = request;
10659        let follow_symbols = state_expected_symbols(atn, transition.target());
10660        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
10661            transition,
10662            index,
10663            atn.max_token_type(),
10664            &expected_symbols,
10665            &follow_symbols,
10666        ) else {
10667            return Vec::new();
10668        };
10669        self.recognize_state(
10670            atn,
10671            RecognizeRequest {
10672                state_number: target,
10673                stop_state,
10674                index,
10675                rule_start_index,
10676                decision_start_index,
10677                init_action_rules,
10678                predicates,
10679                semantics,
10680                rule_args,
10681                member_actions,
10682                return_actions,
10683                local_int_arg,
10684                member_values,
10685                return_values,
10686                rule_alt_number,
10687                track_alt_numbers,
10688                consumed_eof,
10689                committed_decision: false,
10690                precedence,
10691                depth: depth + 1,
10692                recovery_symbols: BTreeSet::new(),
10693                recovery_state: None,
10694            },
10695            visiting,
10696            memo,
10697            expected,
10698        )
10699        .into_iter()
10700        .map(|mut outcome| {
10701            outcome.diagnostics = self
10702                .recognition_arena
10703                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10704            let missing = self.arena_missing_token_node(token_type, index, text.clone());
10705            self.arena_prepend(&mut outcome.nodes, missing);
10706            outcome
10707        })
10708        .collect()
10709    }
10710
10711    /// Attempts to reach `stop_state` and carries semantic actions for the
10712    /// selected parser path.
10713    #[allow(clippy::too_many_lines)]
10714    fn recognize_state(
10715        &mut self,
10716        atn: &Atn,
10717        request: RecognizeRequest<'_>,
10718        visiting: &mut BTreeSet<RecognizeKey>,
10719        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10720        expected: &mut ExpectedTokens,
10721    ) -> Vec<RecognizeOutcome> {
10722        let request_template = request.clone();
10723        let RecognizeRequest {
10724            state_number,
10725            stop_state,
10726            index,
10727            rule_start_index,
10728            decision_start_index,
10729            init_action_rules,
10730            predicates,
10731            semantics,
10732            rule_args,
10733            member_actions,
10734            return_actions,
10735            local_int_arg,
10736            member_values,
10737            return_values,
10738            rule_alt_number,
10739            track_alt_numbers,
10740            consumed_eof,
10741            committed_decision,
10742            precedence,
10743            depth,
10744            recovery_symbols,
10745            recovery_state,
10746        } = request;
10747        if depth > RECOGNITION_DEPTH_LIMIT {
10748            return Vec::new();
10749        }
10750        if state_number == stop_state {
10751            return stop_outcome(
10752                index,
10753                consumed_eof,
10754                rule_alt_number,
10755                member_values,
10756                return_values,
10757            );
10758        }
10759        let key = RecognizeKey {
10760            state_number,
10761            stop_state,
10762            index,
10763            rule_start_index,
10764            decision_start_index,
10765            local_int_arg,
10766            member_values: member_values.clone(),
10767            return_values: return_values.clone(),
10768            rule_alt_number,
10769            track_alt_numbers,
10770            consumed_eof,
10771            committed_decision,
10772            precedence,
10773            recovery_symbols: recovery_symbols.clone(),
10774            recovery_state,
10775        };
10776        if let Some(outcomes) = memo.get(&key) {
10777            return outcomes.clone();
10778        }
10779
10780        let visit_key = key.clone();
10781        if !visiting.insert(visit_key.clone()) {
10782            return Vec::new();
10783        }
10784
10785        let Some(state) = atn.state(state_number) else {
10786            visiting.remove(&visit_key);
10787            return Vec::new();
10788        };
10789        let decision_override_generation = self.decision_override_generation;
10790        let transitions = state.transitions();
10791        let transition_count = transitions.len();
10792        let overridden_transition = if transition_count > 1
10793            && self.semantic_hooks.observes_parser_decisions()
10794        {
10795            atn.decision_to_state()
10796                .iter()
10797                .position(|candidate| candidate == state_number)
10798                .and_then(|decision| {
10799                    self.semantic_hooks
10800                        .parser_decision_override(decision, index, transition_count)
10801                })
10802                .and_then(|alternative| alternative.checked_sub(1))
10803                .filter(|alternative| *alternative < transition_count)
10804        } else {
10805            None
10806        };
10807        if overridden_transition.is_some() {
10808            self.decision_override_generation = self.decision_override_generation.wrapping_add(1);
10809        }
10810        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
10811            Some(index)
10812        } else {
10813            decision_start_index
10814        };
10815        let (epsilon_recovery_symbols, epsilon_recovery_state) =
10816            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
10817        let mut outcomes = Vec::new();
10818        for (transition_index, transition) in transitions.iter().enumerate() {
10819            if overridden_transition.is_some_and(|forced| forced != transition_index) {
10820                continue;
10821            }
10822            let transition_committed =
10823                committed_decision || overridden_transition == Some(transition_index);
10824            let mut transition_request = request_template.clone();
10825            transition_request.committed_decision = transition_committed;
10826            let decision =
10827                transition_decision(atn, state, transition_count, transition_index, predicates);
10828            let next_alt_number = next_alt_number(
10829                state,
10830                transition_count,
10831                transition_index,
10832                rule_alt_number,
10833                track_alt_numbers,
10834            );
10835            let transition_data = transition.data();
10836            match &transition_data {
10837                Transition::Epsilon { target } | Transition::Action { target, .. } => {
10838                    let (action_rule_index, action_index) = match &transition_data {
10839                        Transition::Action {
10840                            rule_index,
10841                            action_index,
10842                            ..
10843                        } => (Some(*rule_index), *action_index),
10844                        _ => (None, None),
10845                    };
10846                    outcomes.extend(self.recognize_epsilon_or_action_step(
10847                        atn,
10848                        &transition_request,
10849                        EpsilonActionStep {
10850                            source_state: state_number,
10851                            target: *target,
10852                            action_rule_index,
10853                            action_index,
10854                            left_recursive_boundary: left_recursive_boundary(atn, state, *target),
10855                            decision,
10856                            decision_start_index: next_decision_start_index,
10857                            alt_number: next_alt_number,
10858                            recovery_symbols: epsilon_recovery_symbols.clone(),
10859                            recovery_state: epsilon_recovery_state,
10860                        },
10861                        RecognizeScratch {
10862                            visiting,
10863                            memo,
10864                            expected,
10865                        },
10866                    ));
10867                }
10868                Transition::Predicate {
10869                    target,
10870                    rule_index,
10871                    pred_index,
10872                    ..
10873                } => {
10874                    let predicate = PredicateEval {
10875                        index,
10876                        rule_index: *rule_index,
10877                        pred_index: *pred_index,
10878                        predicates,
10879                        semantics,
10880                        context: None,
10881                        local_int_arg,
10882                        member_values: &member_values,
10883                    };
10884                    if self.parser_predicate_matches(predicate) {
10885                        let left_recursive_boundary = left_recursive_boundary(atn, state, *target);
10886                        outcomes.extend(
10887                            self.recognize_state(
10888                                atn,
10889                                RecognizeRequest {
10890                                    state_number: *target,
10891                                    stop_state,
10892                                    index,
10893                                    rule_start_index,
10894                                    decision_start_index: next_decision_start_index,
10895                                    init_action_rules,
10896                                    predicates,
10897                                    semantics,
10898                                    rule_args,
10899                                    member_actions,
10900                                    return_actions,
10901                                    local_int_arg,
10902                                    member_values: member_values.clone(),
10903                                    return_values: return_values.clone(),
10904                                    rule_alt_number: next_alt_number,
10905                                    track_alt_numbers,
10906                                    consumed_eof,
10907                                    committed_decision: transition_committed,
10908                                    precedence,
10909                                    depth: depth + 1,
10910                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10911                                    recovery_state: epsilon_recovery_state,
10912                                },
10913                                visiting,
10914                                memo,
10915                                expected,
10916                            )
10917                            .into_iter()
10918                            .map(|mut outcome| {
10919                                prepend_decision(&mut outcome, decision);
10920                                if let Some(rule_index) = left_recursive_boundary {
10921                                    let boundary =
10922                                        self.arena_boundary_node(rule_index, next_alt_number);
10923                                    self.arena_prepend(&mut outcome.nodes, boundary);
10924                                }
10925                                outcome
10926                            }),
10927                        );
10928                    } else if let Some(message) = semantics
10929                        .and_then(|semantics| {
10930                            self.parser_semantic_ir_predicate_failure_message(
10931                                *rule_index,
10932                                *pred_index,
10933                                semantics,
10934                            )
10935                        })
10936                        .or_else(|| {
10937                            self.parser_predicate_failure_message(
10938                                *rule_index,
10939                                *pred_index,
10940                                predicates,
10941                            )
10942                        })
10943                    {
10944                        outcomes.push(self.predicate_failure_recovery(PredicateFailureRecovery {
10945                            rule_index: *rule_index,
10946                            index,
10947                            message,
10948                            member_values: member_values.clone(),
10949                            return_values: return_values.clone(),
10950                            rule_alt_number,
10951                        }));
10952                    } else {
10953                        record_predicate_no_viable(expected, next_decision_start_index, index);
10954                    }
10955                }
10956                Transition::Precedence {
10957                    target,
10958                    precedence: transition_precedence,
10959                } => {
10960                    if *transition_precedence >= precedence {
10961                        outcomes.extend(
10962                            self.recognize_state(
10963                                atn,
10964                                RecognizeRequest {
10965                                    state_number: *target,
10966                                    stop_state,
10967                                    index,
10968                                    rule_start_index,
10969                                    decision_start_index: next_decision_start_index,
10970                                    init_action_rules,
10971                                    predicates,
10972                                    semantics,
10973                                    rule_args,
10974                                    member_actions,
10975                                    return_actions,
10976                                    local_int_arg,
10977                                    member_values: member_values.clone(),
10978                                    return_values: return_values.clone(),
10979                                    rule_alt_number: next_alt_number,
10980                                    track_alt_numbers,
10981                                    consumed_eof,
10982                                    committed_decision: transition_committed,
10983                                    precedence,
10984                                    depth: depth + 1,
10985                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10986                                    recovery_state: epsilon_recovery_state,
10987                                },
10988                                visiting,
10989                                memo,
10990                                expected,
10991                            )
10992                            .into_iter()
10993                            .map(|mut outcome| {
10994                                prepend_decision(&mut outcome, decision);
10995                                outcome
10996                            }),
10997                        );
10998                    }
10999                }
11000                Transition::Rule {
11001                    target,
11002                    rule_index,
11003                    follow_state,
11004                    precedence: rule_precedence,
11005                    ..
11006                } => {
11007                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
11008                        continue;
11009                    };
11010                    let child_local_int_arg =
11011                        rule_local_int_arg(rule_args, state_number, *rule_index, local_int_arg);
11012                    let expected_before_child = expected.clone();
11013                    let children = self.recognize_state(
11014                        atn,
11015                        RecognizeRequest {
11016                            state_number: *target,
11017                            stop_state: child_stop,
11018                            index,
11019                            rule_start_index: index,
11020                            decision_start_index: None,
11021                            init_action_rules,
11022                            predicates,
11023                            semantics,
11024                            rule_args,
11025                            member_actions,
11026                            return_actions,
11027                            local_int_arg: child_local_int_arg,
11028                            member_values: member_values.clone(),
11029                            return_values: BTreeMap::new(),
11030                            rule_alt_number: 0,
11031                            track_alt_numbers,
11032                            consumed_eof: false,
11033                            committed_decision: transition_committed,
11034                            precedence: *rule_precedence,
11035                            depth: depth + 1,
11036                            recovery_symbols: epsilon_recovery_symbols.clone(),
11037                            recovery_state: epsilon_recovery_state,
11038                        },
11039                        visiting,
11040                        memo,
11041                        expected,
11042                    );
11043                    let children = if children.is_empty() {
11044                        self.child_rule_failure_recovery_outcomes(ChildRuleFailureRecovery {
11045                            atn,
11046                            rule_index: *rule_index,
11047                            start_index: index,
11048                            follow_state: *follow_state,
11049                            stop_state,
11050                            member_values: member_values.clone(),
11051                            expected,
11052                        })
11053                    } else {
11054                        children
11055                    };
11056                    let preserve_child_expected =
11057                        self.child_expected_reaches_clean_eof(&children, expected);
11058                    restore_expected(
11059                        &children,
11060                        index,
11061                        expected,
11062                        expected_before_child,
11063                        preserve_child_expected,
11064                    );
11065                    for child in children {
11066                        let child_stop_index =
11067                            self.rule_stop_token_index(child.index, child.consumed_eof);
11068                        let child_nodes = self
11069                            .recognition_arena
11070                            .fold_left_recursive_boundaries(child.nodes);
11071                        let child_node = self.arena_rule_node(ArenaRuleSpec {
11072                            rule_index: *rule_index,
11073                            invoking_state: invoking_state_number(state_number),
11074                            alt_number: child.alt_number,
11075                            start_index: index,
11076                            stop_index: child_stop_index,
11077                            return_values: child.return_values.clone(),
11078                            children: child_nodes,
11079                        });
11080                        outcomes.extend(
11081                            self.recognize_state(
11082                                atn,
11083                                RecognizeRequest {
11084                                    state_number: *follow_state,
11085                                    stop_state,
11086                                    index: child.index,
11087                                    rule_start_index,
11088                                    decision_start_index: next_decision_start_index,
11089                                    init_action_rules,
11090                                    predicates,
11091                                    semantics,
11092                                    rule_args,
11093                                    member_actions,
11094                                    return_actions,
11095                                    local_int_arg,
11096                                    member_values: child.member_values.clone(),
11097                                    return_values: return_values.clone(),
11098                                    rule_alt_number,
11099                                    track_alt_numbers,
11100                                    consumed_eof: consumed_eof || child.consumed_eof,
11101                                    committed_decision: transition_committed
11102                                        && child.index == index,
11103                                    precedence,
11104                                    depth: depth + 1,
11105                                    recovery_symbols: BTreeSet::new(),
11106                                    recovery_state: None,
11107                                },
11108                                visiting,
11109                                memo,
11110                                expected,
11111                            )
11112                            .into_iter()
11113                            .map(|mut outcome| {
11114                                outcome.consumed_eof |= child.consumed_eof;
11115                                outcome.diagnostics = self
11116                                    .recognition_arena
11117                                    .concat_diagnostics(child.diagnostics, outcome.diagnostics);
11118                                let mut decisions = child.decisions.clone();
11119                                decisions.append(&mut outcome.decisions);
11120                                outcome.decisions = decisions;
11121                                prepend_decision(&mut outcome, decision);
11122                                let mut actions = child.actions.clone();
11123                                if init_action_rules.contains(rule_index) {
11124                                    actions.insert(
11125                                        0,
11126                                        ParserAction::new_rule_init(
11127                                            *rule_index,
11128                                            index,
11129                                            Some(*follow_state),
11130                                        ),
11131                                    );
11132                                }
11133                                actions.append(&mut outcome.actions);
11134                                outcome.actions = actions;
11135                                self.arena_prepend(&mut outcome.nodes, child_node);
11136                                outcome
11137                            }),
11138                        );
11139                    }
11140                }
11141                Transition::Atom { target, .. }
11142                | Transition::Range { target, .. }
11143                | Transition::Set { target, .. }
11144                | Transition::NotSet { target, .. }
11145                | Transition::Wildcard { target, .. } => {
11146                    let symbol = self.token_type_at(index);
11147                    if transition_data.matches(symbol, 1, atn.max_token_type()) {
11148                        let next_index = self.consume_index(index, symbol);
11149                        outcomes.extend(
11150                            self.recognize_state(
11151                                atn,
11152                                RecognizeRequest {
11153                                    state_number: *target,
11154                                    stop_state,
11155                                    index: next_index,
11156                                    rule_start_index,
11157                                    decision_start_index: next_decision_start_index,
11158                                    init_action_rules,
11159                                    predicates,
11160                                    semantics,
11161                                    rule_args,
11162                                    member_actions,
11163                                    return_actions,
11164                                    local_int_arg,
11165                                    member_values: member_values.clone(),
11166                                    return_values: return_values.clone(),
11167                                    rule_alt_number: next_alt_number,
11168                                    track_alt_numbers,
11169                                    consumed_eof: consumed_eof || symbol == TOKEN_EOF,
11170                                    committed_decision: false,
11171                                    precedence,
11172                                    depth: depth + 1,
11173                                    recovery_symbols: BTreeSet::new(),
11174                                    recovery_state: None,
11175                                },
11176                                visiting,
11177                                memo,
11178                                expected,
11179                            )
11180                            .into_iter()
11181                            .map(|mut outcome| {
11182                                prepend_decision(&mut outcome, decision);
11183                                outcome.consumed_eof |= symbol == TOKEN_EOF;
11184                                let token = self.arena_token_node(index, false);
11185                                self.arena_prepend(&mut outcome.nodes, token);
11186                                outcome
11187                            }),
11188                        );
11189                    } else {
11190                        let expected_symbols =
11191                            recovery_expected_symbols(atn, state.state_number(), &recovery_symbols);
11192                        if expected_symbols.contains(&symbol) && !transition_committed {
11193                            continue;
11194                        }
11195                        expected.record_transition(index, transition, atn.max_token_type());
11196                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
11197                        let before_recovery = outcomes.len();
11198                        let recovery_request = transition_request.clone();
11199                        if transition_committed {
11200                            outcomes.extend(self.consuming_failure_fallback(
11201                                ConsumingFailureFallback {
11202                                    atn,
11203                                    target: *target,
11204                                    request: recovery_request,
11205                                    symbol,
11206                                    expected_symbols,
11207                                    decision_start_index: next_decision_start_index,
11208                                    decision,
11209                                },
11210                                visiting,
11211                                memo,
11212                                expected,
11213                            ));
11214                            break;
11215                        }
11216                        outcomes.extend(
11217                            self.single_token_deletion_recovery(RecoveryRequest {
11218                                atn,
11219                                transition,
11220                                expected_symbols: expected_symbols.clone(),
11221                                target: *target,
11222                                request: recovery_request.clone(),
11223                                visiting,
11224                                memo,
11225                                expected,
11226                            })
11227                            .into_iter()
11228                            .map(|mut outcome| {
11229                                prepend_decision(&mut outcome, decision);
11230                                outcome
11231                            }),
11232                        );
11233                        if !state_is_left_recursive_rule(atn, state) {
11234                            outcomes.extend(
11235                                self.single_token_insertion_recovery(RecoveryRequest {
11236                                    atn,
11237                                    transition,
11238                                    expected_symbols: expected_symbols.clone(),
11239                                    target: *target,
11240                                    request: recovery_request.clone(),
11241                                    visiting,
11242                                    memo,
11243                                    expected,
11244                                })
11245                                .into_iter()
11246                                .map(|mut outcome| {
11247                                    prepend_decision(&mut outcome, decision);
11248                                    outcome
11249                                }),
11250                            );
11251                        }
11252                        outcomes.extend(self.current_token_deletion_recovery(
11253                            CurrentTokenDeletionRequest {
11254                                atn,
11255                                expected_symbols: expected_symbols.clone(),
11256                                request: recovery_request.clone(),
11257                                visiting,
11258                                memo,
11259                                expected,
11260                            },
11261                        ));
11262                        if outcomes.len() == before_recovery {
11263                            outcomes.extend(self.consuming_failure_fallback(
11264                                ConsumingFailureFallback {
11265                                    atn,
11266                                    target: *target,
11267                                    request: recovery_request,
11268                                    symbol,
11269                                    expected_symbols,
11270                                    decision_start_index: next_decision_start_index,
11271                                    decision,
11272                                },
11273                                visiting,
11274                                memo,
11275                                expected,
11276                            ));
11277                        }
11278                    }
11279                }
11280            }
11281            if self.decision_override_generation != decision_override_generation {
11282                break;
11283            }
11284        }
11285
11286        visiting.remove(&visit_key);
11287        self.record_prediction_diagnostics(atn, state, index, &outcomes);
11288        if matches!(
11289            self.prediction_mode,
11290            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
11291        ) {
11292            discard_recovered_outcomes_if_clean_path_exists(&mut outcomes, &self.recognition_arena);
11293        }
11294        dedupe_outcomes(&mut outcomes, &self.recognition_arena);
11295        memo.insert(key, outcomes.clone());
11296        outcomes
11297    }
11298
11299    /// Follows an epsilon or semantic-action transition while preserving the
11300    /// path-local side effects that may later become generated action output.
11301    fn recognize_epsilon_or_action_step(
11302        &mut self,
11303        atn: &Atn,
11304        request: &RecognizeRequest<'_>,
11305        step: EpsilonActionStep,
11306        scratch: RecognizeScratch<'_>,
11307    ) -> Vec<RecognizeOutcome> {
11308        let RecognizeScratch {
11309            visiting,
11310            memo,
11311            expected,
11312        } = scratch;
11313        let action = step.action_rule_index.map(|rule_index| {
11314            let stop_index = self.rule_stop_token_index(request.index, request.consumed_eof);
11315            step.action_index.map_or_else(
11316                || {
11317                    ParserAction::new(
11318                        step.source_state,
11319                        rule_index,
11320                        request.rule_start_index,
11321                        stop_index,
11322                    )
11323                },
11324                |action_index| {
11325                    ParserAction::new_indexed(
11326                        step.source_state,
11327                        rule_index,
11328                        action_index,
11329                        request.rule_start_index,
11330                        stop_index,
11331                    )
11332                },
11333            )
11334        });
11335        let next_member_values = if action.is_some() {
11336            member_values_after_action(
11337                step.source_state,
11338                request.member_actions,
11339                request.semantics,
11340                &request.member_values,
11341            )
11342        } else {
11343            request.member_values.clone()
11344        };
11345        let next_return_values = action.map_or_else(
11346            || request.return_values.clone(),
11347            |action| {
11348                return_values_after_action(
11349                    step.source_state,
11350                    action.rule_index(),
11351                    request.return_actions,
11352                    request.semantics,
11353                    &request.return_values,
11354                )
11355            },
11356        );
11357
11358        self.recognize_state(
11359            atn,
11360            RecognizeRequest {
11361                state_number: step.target,
11362                stop_state: request.stop_state,
11363                index: request.index,
11364                rule_start_index: request.rule_start_index,
11365                decision_start_index: step.decision_start_index,
11366                init_action_rules: request.init_action_rules,
11367                predicates: request.predicates,
11368                semantics: request.semantics,
11369                rule_args: request.rule_args,
11370                member_actions: request.member_actions,
11371                return_actions: request.return_actions,
11372                local_int_arg: request.local_int_arg,
11373                member_values: next_member_values,
11374                return_values: next_return_values,
11375                rule_alt_number: if step.left_recursive_boundary.is_some() {
11376                    0
11377                } else {
11378                    step.alt_number
11379                },
11380                track_alt_numbers: request.track_alt_numbers,
11381                consumed_eof: request.consumed_eof,
11382                committed_decision: request.committed_decision,
11383                precedence: request.precedence,
11384                depth: request.depth + 1,
11385                recovery_symbols: step.recovery_symbols,
11386                recovery_state: step.recovery_state,
11387            },
11388            visiting,
11389            memo,
11390            expected,
11391        )
11392        .into_iter()
11393        .map(|mut outcome| {
11394            prepend_decision(&mut outcome, step.decision);
11395            if let Some(rule_index) = step.left_recursive_boundary {
11396                let boundary = self.arena_boundary_node(rule_index, step.alt_number);
11397                self.arena_prepend(&mut outcome.nodes, boundary);
11398            }
11399            if let Some(action) = action {
11400                outcome.actions.insert(0, action);
11401            }
11402            outcome
11403        })
11404        .collect()
11405    }
11406
11407    /// Reads the token type at an absolute token-stream index without moving
11408    /// the parser's stream cursor. The fast recognizer probes lookahead at
11409    /// every state visit, so avoiding the seek round-trip is a measurable
11410    /// hot-path win on long inputs.
11411    fn token_type_at(&mut self, index: usize) -> i32 {
11412        if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !self.input.is_filled() {
11413            self.input.fill();
11414        }
11415        self.input.token_type_at_index(index)
11416    }
11417
11418    /// Returns the cached `state_expected_symbols` set for an ATN state.
11419    ///
11420    /// The fast recognizer consults this set on every state visit through
11421    /// `next_recovery_context`; the underlying DFS is a pure function of the
11422    /// ATN, so caching the `Rc` lets clones reduce to a reference bump.
11423    ///
11424    /// Caching is layered through `intern_recovery_symbols` so two ATN states
11425    /// with the same expected-symbol set share one `Rc`. That invariant is
11426    /// what lets `FastRecognizeKey` hash on `recovery_symbols` by pointer
11427    /// without violating the `Hash`/`Eq` contract — `recovery_symbols` is
11428    /// always interned before it ends up in a key.
11429    fn cached_state_expected_symbols(
11430        &mut self,
11431        atn: &Atn,
11432        state_number: usize,
11433    ) -> Rc<BTreeSet<i32>> {
11434        if let Some(cached) = self.state_expected_cache.get(&state_number) {
11435            return Rc::clone(cached);
11436        }
11437        let symbols = state_expected_symbols(atn, state_number);
11438        let entry = self.intern_recovery_symbols(symbols);
11439        self.state_expected_cache
11440            .insert(state_number, Rc::clone(&entry));
11441        entry
11442    }
11443
11444    fn cached_state_expected_token_set(
11445        &mut self,
11446        atn: &Atn,
11447        state_number: usize,
11448    ) -> Rc<TokenBitSet> {
11449        if let Some(cached) = self.state_expected_token_cache.get(&state_number) {
11450            return Rc::clone(cached);
11451        }
11452        // Purely a function of the ATN, so back the per-parser cache with the
11453        // thread-shared one — fresh parser instances (one per parse in
11454        // generated usage) start warm instead of rewalking the ATN.
11455        let symbols = with_shared_atn_caches(atn, |cache| {
11456            if let Some(cached) = cache.state_expected_tokens.get(&state_number) {
11457                return Rc::clone(cached);
11458            }
11459            let symbols = Rc::new(state_expected_token_set(atn, state_number));
11460            cache
11461                .state_expected_tokens
11462                .insert(state_number, Rc::clone(&symbols));
11463            symbols
11464        });
11465        self.state_expected_token_cache
11466            .insert(state_number, Rc::clone(&symbols));
11467        symbols
11468    }
11469
11470    fn cached_state_can_reach_rule_stop(&mut self, atn: &Atn, state_number: usize) -> bool {
11471        if self.rule_stop_reach_cache.len() <= state_number {
11472            self.rule_stop_reach_cache
11473                .resize_with(atn.states().len().max(state_number + 1), || None);
11474        }
11475        if let Some(reaches) = self.rule_stop_reach_cache[state_number] {
11476            return reaches;
11477        }
11478        let reaches = with_shared_atn_caches(atn, |cache| {
11479            *cache
11480                .rule_stop_reach
11481                .entry(state_number)
11482                .or_insert_with(|| state_can_reach_rule_stop(atn, state_number))
11483        });
11484        self.rule_stop_reach_cache[state_number] = Some(reaches);
11485        reaches
11486    }
11487
11488    /// Returns the parser's empty `recovery_symbols` singleton so callers can
11489    /// share an `Rc` instead of allocating new `BTreeSet`s for the common case.
11490    fn empty_recovery_symbols(&self) -> Rc<BTreeSet<i32>> {
11491        Rc::clone(&self.empty_recovery_symbols)
11492    }
11493
11494    /// Returns the interned `Rc` form of a `recovery_symbols` set so the fast
11495    /// recognizer can hash and compare keys by pointer.
11496    ///
11497    /// Every `Rc<BTreeSet<i32>>` that flows into a `FastRecognizeKey` must
11498    /// come from this method or the empty singleton; otherwise two
11499    /// content-equal `Rc`s could end up with different `Rc::as_ptr` values,
11500    /// and the pointer-keyed hash on `FastRecognizeKey` would split equivalent
11501    /// recognition coordinates.
11502    fn intern_recovery_symbols(&mut self, set: BTreeSet<i32>) -> Rc<BTreeSet<i32>> {
11503        if set.is_empty() {
11504            return Rc::clone(&self.empty_recovery_symbols);
11505        }
11506        let candidate = Rc::new(set);
11507        match self.recovery_symbols_intern.get(&candidate) {
11508            Some(existing) => Rc::clone(existing),
11509            None => {
11510                self.recovery_symbols_intern
11511                    .insert(Rc::clone(&candidate), Rc::clone(&candidate));
11512                candidate
11513            }
11514        }
11515    }
11516
11517    /// Returns the cached look-1 entry for a decision state, computing it on
11518    /// first use. Multi-alternative states are visited many times during
11519    /// recognition; sharing the entry through `Rc` keeps the prefilter to one
11520    /// hash lookup per visit.
11521    fn cached_decision_lookahead(
11522        &mut self,
11523        atn: &Atn,
11524        state: AtnState<'_>,
11525        rule_stop_state: usize,
11526    ) -> Rc<DecisionLookahead> {
11527        // Hit the parser-instance cache first. Decision lookahead is purely
11528        // a function of the ATN/state, so on a warm cache we skip the
11529        // thread-local + RefCell + HashMap-entry dance through
11530        // SHARED_ATN_CACHES — which on multi-trans-heavy grammars (C# does
11531        // ~58K multi-trans visits per parse) shows up as RefCell borrow and
11532        // hashmap-entry overhead in profiles.
11533        if let Some(cached) = self.decision_lookahead_cache.get(&state.state_number()) {
11534            return Rc::clone(cached);
11535        }
11536        let entry = with_shared_atn_caches(atn, |cache| {
11537            if let Some(cached) = cache.decision_lookahead.get(&state.state_number()) {
11538                return Rc::clone(cached);
11539            }
11540            let mut entry = DecisionLookahead {
11541                transitions: Vec::with_capacity(state.transitions().len()),
11542            };
11543            for transition in &state.transitions() {
11544                entry.transitions.push(transition_first_set(
11545                    atn,
11546                    transition,
11547                    rule_stop_state,
11548                    &mut cache.first_set,
11549                ));
11550            }
11551            let entry = Rc::new(entry);
11552            cache
11553                .decision_lookahead
11554                .insert(state.state_number(), Rc::clone(&entry));
11555            entry
11556        });
11557        self.decision_lookahead_cache
11558            .insert(state.state_number(), Rc::clone(&entry));
11559        entry
11560    }
11561
11562    fn cached_rule_first_set(
11563        &mut self,
11564        atn: &Atn,
11565        target: usize,
11566        child_stop: usize,
11567    ) -> Rc<FirstSet> {
11568        if self.rule_first_set_cache.len() <= target {
11569            self.rule_first_set_cache
11570                .resize_with(atn.states().len().max(target + 1), || None);
11571        }
11572        if let Some(cached) = self
11573            .rule_first_set_cache
11574            .get(target)
11575            .and_then(Option::as_ref)
11576        {
11577            return Rc::clone(cached);
11578        }
11579        let first = with_shared_first_set_cache(atn, |cache| {
11580            rule_first_set(atn, target, child_stop, cache)
11581        });
11582        self.rule_first_set_cache[target] = Some(Rc::clone(&first));
11583        first
11584    }
11585
11586    fn state_can_reenter_without_consuming(&mut self, atn: &Atn, state_number: usize) -> bool {
11587        let atn_key = SharedAtnCacheKey::for_atn(atn);
11588        if self.empty_cycle_cache_atn != Some(atn_key) {
11589            self.empty_cycle_cache.clear();
11590            self.empty_cycle_cache_atn = Some(atn_key);
11591        }
11592        if self.empty_cycle_cache.len() <= state_number {
11593            self.empty_cycle_cache
11594                .resize_with(atn.state_count().max(state_number + 1), || None);
11595        }
11596        if let Some(cached) = self.empty_cycle_cache[state_number] {
11597            return cached;
11598        }
11599        let mut visited = FxHashSet::with_capacity_and_hasher(64, FxBuildHasher::default());
11600        let result = self.empty_path_reaches_state(atn, state_number, state_number, &mut visited);
11601        self.empty_cycle_cache[state_number] = Some(result);
11602        result
11603    }
11604
11605    fn empty_path_reaches_state(
11606        &mut self,
11607        atn: &Atn,
11608        state_number: usize,
11609        target_state: usize,
11610        visited: &mut FxHashSet<usize>,
11611    ) -> bool {
11612        enum Work {
11613            Visit(usize),
11614            RuleFollow {
11615                target: usize,
11616                rule_index: usize,
11617                follow_state: usize,
11618            },
11619        }
11620
11621        let mut work = vec![Work::Visit(state_number)];
11622        while let Some(item) = work.pop() {
11623            match item {
11624                Work::Visit(state_number) => {
11625                    if !visited.insert(state_number) {
11626                        continue;
11627                    }
11628                    let Some(state) = atn.state(state_number) else {
11629                        continue;
11630                    };
11631                    let transitions = state.transitions();
11632                    for transition_index in (0..transitions.len()).rev() {
11633                        let transition = transitions
11634                            .get(transition_index)
11635                            .expect("in-bounds parser transition");
11636                        let kind = transition.kind();
11637                        let target = transition.target();
11638                        match kind {
11639                            ParserTransitionKind::Atom
11640                            | ParserTransitionKind::Range
11641                            | ParserTransitionKind::Set
11642                            | ParserTransitionKind::NotSet
11643                            | ParserTransitionKind::Wildcard => {}
11644                            ParserTransitionKind::Rule => {
11645                                if target == target_state {
11646                                    return true;
11647                                }
11648                                work.push(Work::RuleFollow {
11649                                    target,
11650                                    rule_index: transition.arg0() as usize,
11651                                    follow_state: transition.arg1() as usize,
11652                                });
11653                                work.push(Work::Visit(target));
11654                            }
11655                            ParserTransitionKind::Epsilon
11656                            | ParserTransitionKind::Predicate
11657                            | ParserTransitionKind::Action
11658                            | ParserTransitionKind::Precedence => {
11659                                if target == target_state {
11660                                    return true;
11661                                }
11662                                work.push(Work::Visit(target));
11663                            }
11664                        }
11665                    }
11666                }
11667                Work::RuleFollow {
11668                    target,
11669                    rule_index,
11670                    follow_state,
11671                } => {
11672                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
11673                        continue;
11674                    };
11675                    if self.cached_rule_first_set(atn, target, child_stop).nullable {
11676                        if follow_state == target_state {
11677                            return true;
11678                        }
11679                        work.push(Work::Visit(follow_state));
11680                    }
11681                }
11682            }
11683        }
11684        false
11685    }
11686
11687    /// Decides whether the clean recognizer should use its full outcome memo
11688    /// table for this coordinate.
11689    fn clean_memo_enabled_for_key(&mut self, key: &FastRecognizeKey) -> bool {
11690        match self.clean_memo_mode {
11691            CleanMemoMode::Promote => true,
11692            CleanMemoMode::Probe => self.observe_clean_memo_probe(key),
11693            CleanMemoMode::Sparse => {
11694                self.clean_memo_sparse_samples += 1;
11695                if self.clean_memo_sparse_samples < CLEAN_MEMO_REPROBE_INTERVAL {
11696                    return false;
11697                }
11698                self.clean_memo_sparse_samples = 0;
11699                self.clean_memo_mode = CleanMemoMode::Probe;
11700                self.clean_memo_probe_samples = 0;
11701                self.clean_memo_probe_repeats = 0;
11702                self.clean_memo_probe_seen.clear();
11703                self.observe_clean_memo_probe(key)
11704            }
11705        }
11706    }
11707
11708    fn observe_clean_memo_probe(&mut self, key: &FastRecognizeKey) -> bool {
11709        self.clean_memo_probe_samples += 1;
11710        if !self.clean_memo_probe_seen.insert(key.clone()) {
11711            self.clean_memo_probe_repeats += 1;
11712        }
11713        if self.clean_memo_probe_repeats >= CLEAN_MEMO_REPEAT_LIMIT {
11714            self.clean_memo_mode = CleanMemoMode::Promote;
11715            self.clean_memo_probe_seen.clear();
11716            return true;
11717        }
11718        if self.clean_memo_probe_samples >= CLEAN_MEMO_PROBE_LIMIT {
11719            self.clean_memo_mode = CleanMemoMode::Sparse;
11720            self.clean_memo_sparse_samples = 0;
11721            self.clean_memo_probe_seen.clear();
11722            return false;
11723        }
11724        true
11725    }
11726
11727    /// Borrows the visible token at an absolute token-stream index.
11728    fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
11729        self.input.get(index)
11730    }
11731
11732    /// Returns the compact token ID at an absolute token-stream index.
11733    fn token_id_at(&self, index: usize) -> Option<TokenId> {
11734        self.input.get_id(index)
11735    }
11736
11737    fn arena_token_node(&mut self, index: usize, error: bool) -> RecognizedNodeId {
11738        let token = self
11739            .token_id_at(index)
11740            .expect("recognized token index must exist in the token store");
11741        let node = if error {
11742            ArenaRecognizedNode::ErrorToken { token }
11743        } else {
11744            ArenaRecognizedNode::Token { token }
11745        };
11746        self.recognition_arena.push_node(node)
11747    }
11748
11749    fn arena_missing_token_node(
11750        &mut self,
11751        token_type: i32,
11752        at_index: usize,
11753        text: String,
11754    ) -> RecognizedNodeId {
11755        let extra = self
11756            .recognition_arena
11757            .push_extra(RecognitionExtra::MissingToken {
11758                token_type,
11759                at_index: u32::try_from(at_index).expect("missing-token stream index fits in u32"),
11760                text,
11761            });
11762        self.recognition_arena
11763            .push_node(ArenaRecognizedNode::MissingToken { extra })
11764    }
11765
11766    fn arena_rule_node(&mut self, spec: ArenaRuleSpec) -> RecognizedNodeId {
11767        let ArenaRuleSpec {
11768            rule_index,
11769            invoking_state,
11770            alt_number,
11771            start_index,
11772            stop_index,
11773            return_values,
11774            children,
11775        } = spec;
11776        let return_values = (!return_values.is_empty()).then(|| {
11777            self.recognition_arena
11778                .push_extra(RecognitionExtra::ReturnValues(return_values))
11779        });
11780        self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
11781            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11782            invoking_state: i32::try_from(invoking_state).expect("invoking state fits in i32"),
11783            alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11784            start_index: u32::try_from(start_index).expect("rule start index fits in u32"),
11785            stop_index: stop_index
11786                .map(|index| u32::try_from(index).expect("rule stop index fits in u32")),
11787            return_values,
11788            children,
11789        })
11790    }
11791
11792    fn arena_boundary_node(&mut self, rule_index: usize, alt_number: usize) -> RecognizedNodeId {
11793        self.recognition_arena
11794            .push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
11795                rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11796                alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11797            })
11798    }
11799
11800    fn arena_prepend(&mut self, sequence: &mut NodeSeqId, node: RecognizedNodeId) {
11801        *sequence = self.recognition_arena.prepend(*sequence, node);
11802    }
11803
11804    // The perf-counters branch reads the process environment, so this cannot
11805    // become const even when Clippy analyzes the branch-free configuration.
11806    #[allow(clippy::missing_const_for_fn)]
11807    fn finish_recognition_arena(&mut self, root: NodeSeqId, diagnostics: DiagnosticSeqId) {
11808        self.last_recognition_arena_root = root;
11809        self.last_recognition_arena_diagnostics = diagnostics;
11810        #[cfg(feature = "perf-counters")]
11811        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
11812            let stats = self.recognition_arena_stats();
11813            #[allow(clippy::print_stderr)]
11814            {
11815                eprintln!("perf recognition_nodes_total={}", stats.total_nodes);
11816                eprintln!("perf recognition_nodes_live={}", stats.live_nodes);
11817                eprintln!("perf recognition_nodes_dead={}", stats.dead_nodes);
11818                eprintln!("perf recognition_nodes_capacity={}", stats.node_capacity);
11819                eprintln!("perf recognition_links_total={}", stats.total_links);
11820                eprintln!("perf recognition_links_live={}", stats.live_links);
11821                eprintln!("perf recognition_links_dead={}", stats.dead_links);
11822                eprintln!("perf recognition_links_capacity={}", stats.link_capacity);
11823                eprintln!("perf recognition_extras_total={}", stats.total_extras);
11824                eprintln!("perf recognition_extras_live={}", stats.live_extras);
11825                eprintln!("perf recognition_extras_dead={}", stats.dead_extras);
11826                eprintln!("perf recognition_extras_capacity={}", stats.extra_capacity);
11827            }
11828        }
11829    }
11830
11831    fn reset_recognition_arena(&mut self) {
11832        self.recognition_arena.reset();
11833        self.last_recognition_arena_root = NodeSeqId::EMPTY;
11834        self.last_recognition_arena_diagnostics = DiagnosticSeqId::EMPTY;
11835    }
11836
11837    /// Normalizes the current token-stream cursor to the next parser-visible
11838    /// token before capturing a rule start boundary.
11839    fn current_visible_index(&mut self) -> usize {
11840        let index = self.input.index();
11841        self.input.seek(index);
11842        self.input.index()
11843    }
11844
11845    /// Reports whether a child rule reached EOF cleanly while also recording
11846    /// an EOF expectation from a longer path inside that child.
11847    fn child_expected_reaches_clean_eof(
11848        &mut self,
11849        children: &[RecognizeOutcome],
11850        expected: &ExpectedTokens,
11851    ) -> bool {
11852        let Some(index) = expected.index else {
11853            return false;
11854        };
11855        self.token_type_at(index) == TOKEN_EOF
11856            && children
11857                .iter()
11858                .any(|child| child.diagnostics.is_empty() && child.index == index)
11859    }
11860
11861    /// Finds the previous token visible to the parser before `index`.
11862    ///
11863    /// The token stream cursor skips hidden-channel tokens, so subtracting one
11864    /// from a visible-token index can point at whitespace. Parser intervals use
11865    /// this helper to stop at the previous visible token while preserving hidden
11866    /// text inside the rendered interval.
11867    fn previous_token_index(&self, index: usize) -> Option<usize> {
11868        self.input.previous_visible_token_index(index)
11869    }
11870
11871    /// Returns the token-stream index used as a rule stop boundary.
11872    ///
11873    /// EOF transitions keep the cursor on EOF, so a rule that consumed EOF must
11874    /// stop at `index` rather than at the previous visible token.
11875    fn rule_stop_token_index(&mut self, index: usize, consumed_eof: bool) -> Option<usize> {
11876        if consumed_eof && self.token_type_at(index) == TOKEN_EOF {
11877            Some(index)
11878        } else {
11879            self.previous_token_index(index)
11880        }
11881    }
11882
11883    /// Stop-token index for a rule's `@after` action, matching the boundary that
11884    /// `finish_rule` records on the rule context.
11885    ///
11886    /// A rule that matched EOF leaves the cursor parked on the EOF token
11887    /// (`CommonTokenStream::consume` does not advance past EOF), so the stop is
11888    /// the current index rather than the previous visible token. Without this,
11889    /// `$stop`/`$text` in an `@after` action on a rule like `r: a* EOF;` would
11890    /// report the token before EOF (or `None` for empty input), diverging from
11891    /// the rule context that `finish_rule` builds.
11892    ///
11893    /// NOTE: this infers `consumed_eof` from the cursor, which is wrong when a
11894    /// rule ends right before EOF without matching it (the cursor is parked on
11895    /// EOF, but the rule did not consume it). Prefer
11896    /// [`Self::after_action_stop_index_for_tree`], which reuses the stop token the
11897    /// rule context already recorded with the real flag. Kept for callers without
11898    /// the rule tree in hand.
11899    #[must_use]
11900    pub fn after_action_stop_index(&mut self, current_index: usize) -> Option<usize> {
11901        let consumed_eof = self.token_type_at(current_index) == TOKEN_EOF;
11902        self.rule_stop_token_index(current_index, consumed_eof)
11903    }
11904
11905    /// Stop-token index for a rule's `@after` action, taken from the stop token
11906    /// the rule context already recorded.
11907    ///
11908    /// `finish_rule` computes the rule stop with the real `consumed_eof` flag, so
11909    /// reading it back keeps `$stop`/`$text` in an `@after` action aligned with
11910    /// the rule context — even when the rule ends immediately before EOF without
11911    /// matching it (cursor parked on EOF, but `consumed_eof` is false). Falls back
11912    /// to the cursor-based inference only when the tree carries no rule stop.
11913    #[must_use]
11914    pub fn after_action_stop_index_for_tree(
11915        &mut self,
11916        tree: ParseTree,
11917        current_index: usize,
11918    ) -> Option<usize> {
11919        if let Some(stop) = self
11920            .node(tree)
11921            .as_rule()
11922            .and_then(crate::tree::RuleNodeView::stop_id)
11923        {
11924            return Some(stop.index());
11925        }
11926        self.after_action_stop_index(current_index)
11927    }
11928
11929    /// Start-token index for a rule's `@after` action, taken from the start token
11930    /// the rule context already recorded.
11931    ///
11932    /// `enter_rule` sets the rule context start to the first visible token (it
11933    /// skips leading hidden-channel tokens), so reading it back keeps `$start` /
11934    /// `$text` in an `@after` action aligned with the rule context — even when the
11935    /// rule begins after a hidden prefix (e.g. leading whitespace) that the raw
11936    /// pre-rule cursor still points at. Falls back to `fallback_index` only when
11937    /// the tree carries no rule start.
11938    #[must_use]
11939    pub fn after_action_start_index_for_tree(
11940        &self,
11941        tree: ParseTree,
11942        fallback_index: usize,
11943    ) -> usize {
11944        if let Some(start) = self
11945            .node(tree)
11946            .as_rule()
11947            .and_then(crate::tree::RuleNodeView::start_id)
11948        {
11949            return start.index();
11950        }
11951        fallback_index
11952    }
11953
11954    /// Returns the rule stop token for a selected parse path.
11955    ///
11956    /// EOF transitions do not advance the token-stream cursor, so an EOF match
11957    /// must use the current token rather than the previous visible token.
11958    fn rule_stop_token_id(&mut self, index: usize, consumed_eof: bool) -> Option<TokenId> {
11959        self.rule_stop_token_index(index, consumed_eof)
11960            .and_then(|token_index| self.token_id_at(token_index))
11961    }
11962
11963    /// Recovers from a semantic predicate with an ANTLR `<fail='...'>` option.
11964    ///
11965    /// Generated Java reports the failed-predicate message at the current
11966    /// lookahead, then consumes until rule recovery can resume. The metadata
11967    /// runtime models the same visible tree shape by keeping skipped tokens as
11968    /// error nodes and returning from the active rule at EOF.
11969    fn predicate_failure_recovery(
11970        &mut self,
11971        request: PredicateFailureRecovery<'_>,
11972    ) -> RecognizeOutcome {
11973        let PredicateFailureRecovery {
11974            rule_index,
11975            index,
11976            message,
11977            member_values,
11978            return_values,
11979            rule_alt_number,
11980        } = request;
11981        let rule_name = self
11982            .rule_names()
11983            .get(rule_index)
11984            .map_or_else(|| rule_index.to_string(), Clone::clone);
11985        let diagnostic = diagnostic_for_token(
11986            self.token_at(index).as_ref(),
11987            format!("rule {rule_name} {message}"),
11988        );
11989        let mut reversed_nodes = NodeSeqId::EMPTY;
11990        let mut next_index = index;
11991        loop {
11992            let symbol = self.token_type_at(next_index);
11993            if symbol == TOKEN_EOF {
11994                break;
11995            }
11996            let error = self.arena_token_node(next_index, true);
11997            self.arena_prepend(&mut reversed_nodes, error);
11998            let after = self.consume_index(next_index, symbol);
11999            if after == next_index {
12000                break;
12001            }
12002            next_index = after;
12003        }
12004        let nodes = self.recognition_arena.reverse_sequence(reversed_nodes);
12005        let diagnostics = self
12006            .recognition_arena
12007            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
12008        RecognizeOutcome {
12009            index: next_index,
12010            consumed_eof: false,
12011            alt_number: rule_alt_number,
12012            member_values,
12013            return_values,
12014            diagnostics,
12015            decisions: Vec::new(),
12016            actions: Vec::new(),
12017            nodes,
12018        }
12019    }
12020
12021    /// Evaluates a user hook for a predicate coordinate that has no generated
12022    /// runtime table entry.
12023    fn parser_semantic_hook_result(
12024        &mut self,
12025        request: ParserSemanticHookRequest<'_>,
12026    ) -> Option<bool> {
12027        let ParserSemanticHookRequest {
12028            index,
12029            rule_index,
12030            pred_index,
12031            context,
12032            local_int_arg,
12033            member_values,
12034        } = request;
12035        let rule_name = self.rule_names().get(rule_index).cloned();
12036        self.input.seek(index);
12037        let input = &mut self.input;
12038        let semantic_hooks = &mut self.semantic_hooks;
12039        let mut ctx = ParserSemCtx {
12040            input,
12041            tree_storage: &self.tree,
12042            rule_index,
12043            coordinate_index: pred_index,
12044            rule_name,
12045            context,
12046            tree: None,
12047            local_int_arg,
12048            member_values,
12049            action: None,
12050        };
12051        semantic_hooks.sempred(&mut ctx, rule_index, pred_index)
12052    }
12053
12054    /// Re-inserts unknown-predicate coordinates recorded before a nested
12055    /// interpreted recognition, preserving order and skipping any the nested
12056    /// call already recorded, so a generated parent's fail-loud coordinates
12057    /// survive descending into an interpreted child.
12058    fn restore_prior_unknown_predicate_hits(&mut self, prior: Vec<(usize, usize)>) {
12059        if prior.is_empty() {
12060            return;
12061        }
12062        let mut merged = prior;
12063        for coordinate in std::mem::take(&mut self.unknown_predicate_hits) {
12064            if !merged.contains(&coordinate) {
12065                merged.push(coordinate);
12066            }
12067        }
12068        self.unknown_predicate_hits = merged;
12069    }
12070
12071    /// Re-inserts unhandled action coordinates recorded before a nested
12072    /// committed parse so only that child parse's misses affect its result.
12073    fn restore_prior_unhandled_action_hits(&mut self, prior: Vec<(usize, usize)>) {
12074        if prior.is_empty() {
12075            return;
12076        }
12077        let mut merged = prior;
12078        for coordinate in std::mem::take(&mut self.unhandled_action_hits) {
12079            if !merged.contains(&coordinate) {
12080                merged.push(coordinate);
12081            }
12082        }
12083        self.unhandled_action_hits = merged;
12084    }
12085
12086    /// Applies the active [`UnknownSemanticPolicy`] to a predicate coordinate
12087    /// that has no entry in the generated predicate table.
12088    ///
12089    /// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded and
12090    /// the guarded path is abandoned; the parse entry surfaces the recorded
12091    /// coordinates as [`AntlrError::Unsupported`] once recognition finishes,
12092    /// because a parse that consulted an unknown predicate is unreliable no
12093    /// matter which paths were ultimately selected.
12094    fn unknown_predicate_result(&mut self, rule_index: usize, pred_index: usize) -> bool {
12095        apply_unknown_predicate_policy(
12096            self.unknown_predicate_policy,
12097            rule_index,
12098            pred_index,
12099            &mut self.unknown_predicate_hits,
12100        )
12101    }
12102
12103    /// Builds the fail-loud error for unknown predicate coordinates recorded
12104    /// by the current parse, if any.
12105    fn unknown_semantic_error(&self) -> Option<AntlrError> {
12106        use std::fmt::Write as _;
12107        if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
12108            return None;
12109        }
12110        let mut message = String::new();
12111        for (rule_index, pred_index) in &self.unknown_predicate_hits {
12112            if !message.is_empty() {
12113                message.push_str("; ");
12114            }
12115            let _ = match self.rule_names().get(*rule_index) {
12116                Some(rule_name) => write!(
12117                    message,
12118                    "unsupported semantic predicate: rule={rule_name}({rule_index}) pred_index={pred_index}"
12119                ),
12120                None => write!(
12121                    message,
12122                    "unsupported semantic predicate: rule_index={rule_index} pred_index={pred_index}"
12123                ),
12124            };
12125        }
12126        for (rule_index, source_state) in &self.unhandled_action_hits {
12127            if !message.is_empty() {
12128                message.push_str("; ");
12129            }
12130            let _ = match self.rule_names().get(*rule_index) {
12131                Some(rule_name) => write!(
12132                    message,
12133                    "unhandled semantic action: rule={rule_name}({rule_index}) state={source_state}"
12134                ),
12135                None => write!(
12136                    message,
12137                    "unhandled semantic action: rule_index={rule_index} state={source_state}"
12138                ),
12139            };
12140        }
12141        Some(AntlrError::Unsupported(message))
12142    }
12143
12144    /// Evaluates one lowered predicate expression at the requested input
12145    /// position.
12146    ///
12147    /// This sits in the prediction hot loop, so the context borrows the
12148    /// speculative member state read-only and the rule name by reference —
12149    /// no per-evaluation allocation. Only the hook escape path materializes
12150    /// owned copies, and only when a hook is actually consulted.
12151    fn parser_semir_predicate_matches(
12152        &mut self,
12153        semantics: &ParserSemantics,
12154        predicate: &ParserSemanticPredicate,
12155        request: ParserSemanticHookRequest<'_>,
12156    ) -> bool {
12157        self.input.seek(request.index);
12158        let rule_name = self
12159            .data
12160            .rule_names()
12161            .get(request.rule_index)
12162            .map(String::as_str);
12163        let unknown_predicate_policy = self.unknown_predicate_policy;
12164        let mut ctx = ParserSemIrCtx {
12165            input: &mut self.input,
12166            tree_storage: &self.tree,
12167            semantic_hooks: &mut self.semantic_hooks,
12168            rule_index: request.rule_index,
12169            coordinate_index: request.pred_index,
12170            rule_name,
12171            context: request.context,
12172            local_int_arg: request.local_int_arg,
12173            member_values: request.member_values,
12174            invoked_predicates: &mut self.invoked_predicates,
12175            unknown_predicate_policy,
12176            unknown_predicate_hits: &mut self.unknown_predicate_hits,
12177        };
12178        semir::eval_pred(&semantics.ir, predicate.expr, &mut ctx)
12179    }
12180
12181    fn fast_parser_predicate_matches(
12182        &mut self,
12183        context: Option<FastPredicateContext<'_>>,
12184        transition: ParserTransition<'_>,
12185        index: usize,
12186    ) -> bool {
12187        let Some(context) = context else {
12188            return true;
12189        };
12190        let rule_index = transition.arg0() as usize;
12191        let pred_index = transition.arg1() as usize;
12192        let key = (index, rule_index, pred_index);
12193        if let Some(result) = self.fast_predicate_cache.get(&key) {
12194            return *result;
12195        }
12196        let result = self.parser_predicate_matches(PredicateEval {
12197            index,
12198            rule_index,
12199            pred_index,
12200            predicates: context.predicates,
12201            semantics: context.semantics,
12202            context: None,
12203            local_int_arg: None,
12204            member_values: context.member_values,
12205        });
12206        self.fast_predicate_cache.insert(key, result);
12207        result
12208    }
12209
12210    fn parser_predicate_matches(&mut self, eval: PredicateEval<'_>) -> bool {
12211        let PredicateEval {
12212            index,
12213            rule_index,
12214            pred_index,
12215            predicates,
12216            semantics,
12217            context,
12218            local_int_arg,
12219            member_values,
12220        } = eval;
12221        if let Some((semantics, predicate)) = semantics.and_then(|semantics| {
12222            semantics
12223                .predicates
12224                .iter()
12225                .find(|predicate| {
12226                    predicate.rule_index == rule_index && predicate.pred_index == pred_index
12227                })
12228                .map(|predicate| (semantics, predicate))
12229        }) {
12230            return self.parser_semir_predicate_matches(
12231                semantics,
12232                predicate,
12233                ParserSemanticHookRequest {
12234                    index,
12235                    rule_index,
12236                    pred_index,
12237                    context,
12238                    local_int_arg,
12239                    member_values,
12240                },
12241            );
12242        }
12243        let Some((_, _, predicate)) = predicates
12244            .iter()
12245            .find(|(rule, pred, _)| *rule == rule_index && *pred == pred_index)
12246        else {
12247            if let Some(result) = self.parser_semantic_hook_result(ParserSemanticHookRequest {
12248                index,
12249                rule_index,
12250                pred_index,
12251                context,
12252                local_int_arg,
12253                member_values,
12254            }) {
12255                return result;
12256            }
12257            return self.unknown_predicate_result(rule_index, pred_index);
12258        };
12259        self.input.seek(index);
12260        match predicate {
12261            ParserPredicate::True => true,
12262            ParserPredicate::False => false,
12263            ParserPredicate::FalseWithMessage { .. } => false,
12264            ParserPredicate::Invoke { value } => {
12265                let key = (rule_index, pred_index);
12266                if !self.invoked_predicates.contains(&key) {
12267                    self.invoked_predicates.push(key);
12268                    use std::io::Write as _;
12269                    let mut stdout = std::io::stdout().lock();
12270                    let _ = writeln!(stdout, "eval={value}");
12271                }
12272                *value
12273            }
12274            ParserPredicate::LookaheadTextEquals { offset, text } => self
12275                .input
12276                .lt(*offset)
12277                .is_some_and(|token| Token::text(&token) == Some(*text)),
12278            ParserPredicate::LookaheadNotEquals { offset, token_type } => {
12279                self.la(*offset) != *token_type
12280            }
12281            ParserPredicate::TokenPairAdjacent => {
12282                let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
12283                    return false;
12284                };
12285                let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
12286                    return false;
12287                };
12288                first + 1 == second
12289            }
12290            ParserPredicate::ContextChildRuleTextNotEquals { rule_index, text } => context
12291                .and_then(|context| {
12292                    context
12293                        .child_rules(&self.tree, self.input.token_store(), *rule_index)
12294                        .next()
12295                        .map(crate::tree::RuleNodeView::text)
12296                })
12297                .is_none_or(|actual| actual != *text),
12298            ParserPredicate::LocalIntEquals { value } => {
12299                local_int_arg.is_none_or(|(_, actual)| actual == *value)
12300            }
12301            ParserPredicate::LocalIntLessOrEqual { value } => {
12302                local_int_arg.is_none_or(|(_, actual)| actual <= *value)
12303            }
12304            ParserPredicate::MemberModuloEquals {
12305                member,
12306                modulus,
12307                value,
12308                equals,
12309            } => {
12310                if *modulus == 0 {
12311                    return false;
12312                }
12313                let actual = member_values.scalar(*member).unwrap_or_default() % *modulus;
12314                (actual == *value) == *equals
12315            }
12316            ParserPredicate::MemberEquals {
12317                member,
12318                value,
12319                equals,
12320            } => {
12321                let actual = member_values.scalar(*member).unwrap_or_default();
12322                (actual == *value) == *equals
12323            }
12324        }
12325    }
12326
12327    /// Returns a generated fail-option message for a predicate coordinate.
12328    fn parser_predicate_failure_message(
12329        &self,
12330        rule_index: usize,
12331        pred_index: usize,
12332        predicates: &[(usize, usize, ParserPredicate)],
12333    ) -> Option<&'static str> {
12334        predicates
12335            .iter()
12336            .find_map(|(rule, pred, predicate)| match predicate {
12337                ParserPredicate::FalseWithMessage { message }
12338                    if *rule == rule_index && *pred == pred_index =>
12339                {
12340                    Some(*message)
12341                }
12342                _ => None,
12343            })
12344    }
12345
12346    /// Returns a generated fail-option message for a `SemIR` predicate
12347    /// coordinate.
12348    pub fn parser_semantic_ir_predicate_failure_message(
12349        &self,
12350        rule_index: usize,
12351        pred_index: usize,
12352        semantics: &ParserSemantics,
12353    ) -> Option<&'static str> {
12354        semantics
12355            .predicates
12356            .iter()
12357            .find(|predicate| {
12358                predicate.rule_index == rule_index && predicate.pred_index == pred_index
12359            })
12360            .and_then(|predicate| predicate.failure_message)
12361    }
12362
12363    /// Returns the token-stream index after consuming `symbol` at `index`.
12364    ///
12365    /// EOF is not advanced by ANTLR token streams, so EOF transitions keep the
12366    /// index stable and rely on `consumed_eof` to record that EOF was matched.
12367    /// The parser's stream cursor is left untouched: speculative recognition
12368    /// reads ahead by absolute index, so paying for `seek` on every visited
12369    /// state would dominate the hot path. Real consumption is committed by
12370    /// `parse_atn_rule` via `seek` once a viable outcome is selected.
12371    fn consume_index(&mut self, index: usize, symbol: i32) -> usize {
12372        if symbol == TOKEN_EOF {
12373            return index;
12374        }
12375        self.input.next_visible_after(index)
12376    }
12377
12378    /// Builds ANTLR's no-viable-alternative diagnostic for an ambiguous
12379    /// decision that failed after consuming a shared prefix.
12380    fn no_viable_alternative(&self, start_index: usize, error_index: usize) -> ParserDiagnostic {
12381        let text = display_input_text(&self.input.text(start_index, error_index));
12382        diagnostic_for_token(
12383            self.token_at(error_index).as_ref(),
12384            format!("no viable alternative at input '{text}'"),
12385        )
12386    }
12387
12388    /// Selects the diagnostic for a failed consuming transition after all
12389    /// recovery repairs have been ruled out.
12390    fn recovery_failure_diagnostic(
12391        &self,
12392        index: usize,
12393        decision_start_index: Option<usize>,
12394        expected_symbols: &BTreeSet<i32>,
12395    ) -> ParserDiagnostic {
12396        if expected_symbols.len() > 1 {
12397            if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
12398                return self.no_viable_alternative(decision_start, index);
12399            }
12400        }
12401        diagnostic_for_token(
12402            self.token_at(index).as_ref(),
12403            format!(
12404                "mismatched input {} expecting {}",
12405                self.token_at(index)
12406                    .as_ref()
12407                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12408                self.expected_symbols_display(expected_symbols)
12409            ),
12410        )
12411    }
12412
12413    /// Builds the EOF diagnostic used when ANTLR unwinds a failed nested rule
12414    /// instead of inserting missing tokens in the caller.
12415    fn eof_rule_recovery_diagnostic(
12416        &self,
12417        index: usize,
12418        expected_symbols: &BTreeSet<i32>,
12419        expected: &ExpectedTokens,
12420    ) -> ParserDiagnostic {
12421        let symbols = if expected.index == Some(index) && !expected.symbols.is_empty() {
12422            &expected.symbols
12423        } else {
12424            expected_symbols
12425        };
12426        diagnostic_for_token(
12427            self.token_at(index).as_ref(),
12428            format!(
12429                "mismatched input {} expecting {}",
12430                self.token_at(index)
12431                    .as_ref()
12432                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12433                self.expected_symbols_display(symbols)
12434            ),
12435        )
12436    }
12437
12438    /// Returns token text for a buffered token interval used by generated
12439    /// `$text` actions.
12440    ///
12441    /// ANTLR treats EOF as a range boundary rather than printable input text,
12442    /// even when an action interval explicitly stops at the EOF token.
12443    pub fn text_interval(&self, start: usize, stop: Option<usize>) -> String {
12444        let Some(stop) = stop else {
12445            return String::new();
12446        };
12447        let stop = if self
12448            .token_at(stop)
12449            .is_some_and(|token| token.token_type() == TOKEN_EOF)
12450        {
12451            let Some(previous) = self.previous_token_index(stop) else {
12452                return String::new();
12453            };
12454            previous
12455        } else {
12456            stop
12457        };
12458        self.input.text(start, stop)
12459    }
12460
12461    /// Resets per-parse prediction diagnostics while keeping the parser-level
12462    /// reporting flag configured by generated harness code.
12463    fn clear_prediction_diagnostics(&mut self) {
12464        self.prediction_diagnostics.clear();
12465        self.reported_prediction_diagnostics.clear();
12466    }
12467
12468    /// Drops every per-parse cache that depends on ATN identity or pins
12469    /// recovery-symbol allocations.
12470    ///
12471    /// `BaseParser::parse_atn_rule` takes `&Atn` on each invocation, so the
12472    /// same parser instance can legally be driven against different grammars
12473    /// in sequence. The four caches reset here are keyed by raw ATN
12474    /// coordinates (state numbers, rule indexes) and would silently hand back
12475    /// entries from a previous ATN if reused — pruning lookahead against the
12476    /// wrong transitions or pinning recovery `Rc<BTreeSet<i32>>` allocations
12477    /// for the rest of the process. Clearing them on every parse entry keeps
12478    /// the perf wins (caches still amortize within one parse) without making
12479    /// long-lived parsers leak memory or surface stale ATN data:
12480    ///
12481    /// * `rule_first_set_cache` and `decision_lookahead_cache` are pure
12482    ///   functions of the ATN's state graph.
12483    /// * `state_expected_cache`, `state_expected_token_cache`,
12484    ///   `rule_stop_reach_cache`, and
12485    ///   `recovery_symbols_intern` together form
12486    ///   the identity invariant that lets `FastRecognizeKey` hash
12487    ///   `recovery_symbols` by pointer; they have to be cleared in lockstep
12488    ///   so a stale interned `Rc` cannot outlive its map entry.
12489    /// * `empty_cycle_cache` is grammar-static and carries its own ATN key, so
12490    ///   it is retained here and invalidated lazily when the ATN changes.
12491    fn reset_per_parse_caches(&mut self) {
12492        self.rule_first_set_cache.clear();
12493        self.decision_lookahead_cache.clear();
12494        self.ll1_decision_cache.clear();
12495        self.fast_predicate_cache.clear();
12496        self.rule_stop_reach_cache.clear();
12497        self.clean_memo_mode = CleanMemoMode::Probe;
12498        self.clean_memo_probe_seen.clear();
12499        self.clean_memo_probe_samples = 0;
12500        self.clean_memo_probe_repeats = 0;
12501        self.clean_memo_sparse_samples = 0;
12502        self.recovery_symbols_intern.clear();
12503        self.state_expected_cache.clear();
12504        self.state_expected_token_cache.clear();
12505    }
12506
12507    /// Buffers ANTLR-style diagnostic-listener messages for decision states
12508    /// where multiple clean alternatives survive full-context recognition.
12509    fn record_prediction_diagnostics(
12510        &mut self,
12511        atn: &Atn,
12512        state: AtnState<'_>,
12513        start_index: usize,
12514        outcomes: &[RecognizeOutcome],
12515    ) {
12516        if !self.report_diagnostic_errors || state.transitions().len() < 2 {
12517            return;
12518        }
12519        let Some(decision) = atn
12520            .decision_to_state()
12521            .iter()
12522            .position(|state_number| state_number == state.state_number())
12523        else {
12524            return;
12525        };
12526        let Some(rule_index) = state.rule_index() else {
12527            return;
12528        };
12529        let mut alts_by_end = BTreeMap::<usize, BTreeSet<usize>>::new();
12530        for outcome in outcomes
12531            .iter()
12532            .filter(|outcome| outcome.diagnostics.is_empty())
12533        {
12534            let Some(alt) = outcome.decisions.first() else {
12535                continue;
12536            };
12537            alts_by_end
12538                .entry(outcome.index)
12539                .or_default()
12540                .insert(alt + 1);
12541        }
12542        let Some((&end_index, ambig_alts)) = alts_by_end
12543            .iter()
12544            .filter(|(_, alts)| alts.len() > 1)
12545            .max_by_key(|(end, _)| *end)
12546        else {
12547            return;
12548        };
12549        let rule_name = self
12550            .rule_names()
12551            .get(rule_index)
12552            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
12553        let stop_index = self.previous_token_index(end_index).unwrap_or(start_index);
12554        let input = display_input_text(&self.input.text(start_index, stop_index));
12555        let alts = ambig_alts
12556            .iter()
12557            .map(usize::to_string)
12558            .collect::<Vec<_>>()
12559            .join(", ");
12560        let key = (decision, start_index, format!("{alts}:{input}"));
12561        if !self.reported_prediction_diagnostics.insert(key) {
12562            return;
12563        }
12564        let start_diagnostic = diagnostic_for_token(
12565            self.token_at(start_index),
12566            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
12567        );
12568        let stop_diagnostic = diagnostic_for_token(
12569            self.token_at(stop_index),
12570            format!(
12571                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
12572            ),
12573        );
12574        self.prediction_diagnostics.push(start_diagnostic);
12575        self.prediction_diagnostics.push(stop_diagnostic);
12576    }
12577
12578    /// Formats the tokens expected from an ATN state using ANTLR display names.
12579    pub fn expected_tokens_at_state(&self, atn: &Atn, state_number: usize) -> String {
12580        expected_symbols_display(
12581            &state_expected_symbols(atn, state_number),
12582            self.vocabulary(),
12583        )
12584    }
12585
12586    /// Expected-token set at the parser's current ATN state — ANTLR's
12587    /// `getExpectedTokens()`. Generated recognizers expose this as
12588    /// `self.expected_tokens()` for embedded test actions
12589    /// (`self.expected_tokens().to_token_string(self.vocabulary())`).
12590    pub fn expected_tokens_current(&self, atn: &Atn) -> ExpectedTokenSet {
12591        let state = usize::try_from(self.data().state()).unwrap_or(0);
12592        ExpectedTokenSet {
12593            symbols: state_expected_symbols(atn, state),
12594        }
12595    }
12596
12597    /// Enables the bail error strategy: the first syntax error aborts the
12598    /// parse instead of recovering.
12599    pub const fn set_bail_on_error(&mut self, bail: bool) {
12600        self.bail_on_error = bail;
12601    }
12602
12603    /// Whether the bail error strategy is active.
12604    #[must_use]
12605    pub const fn bail_on_error(&self) -> bool {
12606        self.bail_on_error
12607    }
12608
12609    /// Names of the rules on the live invocation stack, current rule first —
12610    /// ANTLR's `getRuleInvocationStack()`.
12611    pub fn rule_invocation_stack(&self) -> Vec<String> {
12612        self.rule_context_stack
12613            .iter()
12614            .rev()
12615            .map(|frame| {
12616                self.data()
12617                    .rule_names()
12618                    .get(frame.rule_index)
12619                    .cloned()
12620                    .unwrap_or_else(|| format!("<{}>", frame.rule_index))
12621            })
12622            .collect()
12623    }
12624
12625    /// Invoking-state chain for the active rule context, current rule first.
12626    ///
12627    /// The root frame is excluded, matching Java's `RuleContext.toString()`.
12628    pub fn active_invocation_states(&self) -> Vec<isize> {
12629        self.rule_context_stack
12630            .iter()
12631            .skip(1)
12632            .rev()
12633            .map(|frame| frame.invoking_state)
12634            .collect()
12635    }
12636
12637    /// Formats a buffered token in ANTLR's diagnostic token display form.
12638    pub fn token_display_at(&self, index: usize) -> Option<String> {
12639        self.token_at(index).map(|token| format!("{token}"))
12640    }
12641}
12642
12643impl<'atn, S, H> DirectAdaptiveParser<'atn, '_, S, H>
12644where
12645    S: TokenSource,
12646    H: SemanticHooks,
12647{
12648    fn parse_rule(
12649        &mut self,
12650        rule_index: usize,
12651        invoking_state: isize,
12652        precedence: i32,
12653    ) -> DirectAdaptiveParseResult<ParseTree> {
12654        let start_state = self.atn.rule_to_start_state().get(rule_index).ok_or(
12655            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::MissingAtn),
12656        )?;
12657        let stop_state = self
12658            .atn
12659            .rule_to_stop_state()
12660            .get(rule_index)
12661            .filter(|state| *state != usize::MAX)
12662            .ok_or(DirectAdaptiveParseControl::Fallback(
12663                DirectAdaptiveFallback::MissingAtn,
12664            ))?;
12665        let start_index = self.parser.current_visible_index();
12666        let mut context = ParserRuleContext::new(rule_index, invoking_state);
12667        if let Some(token) = self.parser.token_id_at(start_index) {
12668            self.parser.set_context_start(&mut context, token);
12669        }
12670        let mut state_number = start_state;
12671        let mut consumed_eof = false;
12672        while state_number != stop_state {
12673            self.step()?;
12674            let (transition, boundary) = self.next_transition(state_number, precedence)?;
12675            if boundary.is_some() {
12676                return Err(DirectAdaptiveParseControl::Fallback(
12677                    DirectAdaptiveFallback::LeftRecursiveBoundary,
12678                ));
12679            }
12680            match transition.data() {
12681                Transition::Epsilon { target } => {
12682                    state_number = target;
12683                }
12684                Transition::Precedence {
12685                    target,
12686                    precedence: transition_precedence,
12687                } => {
12688                    if transition_precedence < precedence {
12689                        return Err(DirectAdaptiveParseControl::Fallback(
12690                            DirectAdaptiveFallback::Precedence,
12691                        ));
12692                    }
12693                    state_number = target;
12694                }
12695                Transition::Rule {
12696                    rule_index,
12697                    follow_state,
12698                    precedence: rule_precedence,
12699                    ..
12700                } => {
12701                    let child = self.parse_rule(
12702                        rule_index,
12703                        invoking_state_number(state_number),
12704                        rule_precedence,
12705                    )?;
12706                    if self.parser.build_parse_trees {
12707                        self.parser.tree.add_child(&mut context, child);
12708                    }
12709                    state_number = follow_state;
12710                }
12711                Transition::Atom { .. }
12712                | Transition::Range { .. }
12713                | Transition::Set { .. }
12714                | Transition::NotSet { .. }
12715                | Transition::Wildcard { .. } => {
12716                    let (matched_eof, child) = self.consume_transition(transition)?;
12717                    consumed_eof |= matched_eof;
12718                    if let Some(child) = child {
12719                        self.parser.tree.add_child(&mut context, child);
12720                    }
12721                    state_number = transition.target();
12722                }
12723                Transition::Predicate { .. } => {
12724                    return Err(DirectAdaptiveParseControl::Fallback(
12725                        DirectAdaptiveFallback::Predicate,
12726                    ));
12727                }
12728                Transition::Action { .. } => {
12729                    return Err(DirectAdaptiveParseControl::Fallback(
12730                        DirectAdaptiveFallback::Action,
12731                    ));
12732                }
12733            }
12734        }
12735
12736        let stop_index = self
12737            .parser
12738            .rule_stop_token_index(self.parser.input.index(), consumed_eof);
12739        if let Some(token) = stop_index.and_then(|index| self.parser.token_id_at(index)) {
12740            self.parser.set_context_stop(&mut context, token);
12741        }
12742        Ok(self.parser.rule_node(context))
12743    }
12744
12745    const fn step(&mut self) -> DirectAdaptiveParseResult<()> {
12746        self.steps += 1;
12747        if self.steps > ADAPTIVE_DIRECT_STEP_LIMIT {
12748            return Err(DirectAdaptiveParseControl::Fallback(
12749                DirectAdaptiveFallback::StepLimit,
12750            ));
12751        }
12752        Ok(())
12753    }
12754
12755    fn next_transition(
12756        &mut self,
12757        state_number: usize,
12758        precedence: i32,
12759    ) -> DirectAdaptiveParseResult<(ParserTransition<'atn>, Option<usize>)> {
12760        let state = self
12761            .atn
12762            .state(state_number)
12763            .ok_or(DirectAdaptiveParseControl::Fallback(
12764                DirectAdaptiveFallback::MissingAtn,
12765            ))?;
12766        if state.is_rule_stop() {
12767            return Err(DirectAdaptiveParseControl::Fallback(
12768                DirectAdaptiveFallback::RuleStop,
12769            ));
12770        }
12771        let transition_index =
12772            self.transition_index(state_number, state.transitions().len(), precedence)?;
12773        let transition = state.transitions().get(transition_index).ok_or(
12774            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::NoTransition),
12775        )?;
12776        let boundary = match &transition.data() {
12777            Transition::Epsilon { target } | Transition::Precedence { target, .. } => {
12778                left_recursive_boundary(self.atn, state, *target)
12779            }
12780            _ => None,
12781        };
12782        Ok((transition, boundary))
12783    }
12784
12785    fn transition_index(
12786        &mut self,
12787        state_number: usize,
12788        transition_count: usize,
12789        precedence: i32,
12790    ) -> DirectAdaptiveParseResult<usize> {
12791        match transition_count {
12792            0 => Err(DirectAdaptiveParseControl::Fallback(
12793                DirectAdaptiveFallback::NoTransition,
12794            )),
12795            1 => Ok(0),
12796            _ => {
12797                if let Some(alt) = self.ll1_transition_index(state_number, transition_count)? {
12798                    return Ok(alt);
12799                }
12800                let decision = self
12801                    .decision_by_state
12802                    .get(state_number)
12803                    .and_then(|decision| *decision)
12804                    .ok_or(DirectAdaptiveParseControl::Fallback(
12805                        DirectAdaptiveFallback::UnknownDecision,
12806                    ))?;
12807                let prediction = self
12808                    .simulator
12809                    .adaptive_predict_stream_info_with_precedence(
12810                        decision,
12811                        direct_precedence(precedence),
12812                        &mut self.parser.input,
12813                    )
12814                    .map_err(|_| {
12815                        DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::Prediction)
12816                    })?;
12817                if prediction.has_semantic_context {
12818                    return Err(DirectAdaptiveParseControl::Fallback(
12819                        DirectAdaptiveFallback::SemanticContext,
12820                    ));
12821                }
12822                prediction
12823                    .alt
12824                    .checked_sub(1)
12825                    .filter(|index| *index < transition_count)
12826                    .ok_or(DirectAdaptiveParseControl::Fallback(
12827                        DirectAdaptiveFallback::InvalidAlt,
12828                    ))
12829            }
12830        }
12831    }
12832
12833    fn ll1_transition_index(
12834        &mut self,
12835        state_number: usize,
12836        transition_count: usize,
12837    ) -> DirectAdaptiveParseResult<Option<usize>> {
12838        let state = self
12839            .atn
12840            .state(state_number)
12841            .ok_or(DirectAdaptiveParseControl::Fallback(
12842                DirectAdaptiveFallback::MissingAtn,
12843            ))?;
12844        if state.precedence_rule_decision() {
12845            return Ok(None);
12846        }
12847        let Some(rule_stop) = state
12848            .rule_index()
12849            .and_then(|rule_index| self.atn.rule_to_stop_state().get(rule_index))
12850        else {
12851            return Ok(None);
12852        };
12853        let symbol = self.parser.input.la_token(1);
12854        let entry = self
12855            .parser
12856            .cached_decision_lookahead(self.atn, state, rule_stop);
12857        Ok(
12858            ll1_greedy_alt(&entry, symbol, state.non_greedy())
12859                .filter(|alt| *alt < transition_count),
12860        )
12861    }
12862
12863    fn consume_transition(
12864        &mut self,
12865        transition: ParserTransition<'_>,
12866    ) -> DirectAdaptiveParseResult<(bool, Option<ParseTree>)> {
12867        let symbol = self.parser.input.la_token(1);
12868        if !transition.matches(symbol, 1, self.atn.max_token_type()) {
12869            return Err(DirectAdaptiveParseControl::Fallback(
12870                DirectAdaptiveFallback::TokenMismatch,
12871            ));
12872        }
12873        let token = self
12874            .parser
12875            .input
12876            .lt_id(1)
12877            .ok_or(DirectAdaptiveParseControl::Fallback(
12878                DirectAdaptiveFallback::TokenMismatch,
12879            ))?;
12880        let matched_eof = symbol == TOKEN_EOF;
12881        if !matched_eof {
12882            self.parser.consume();
12883        }
12884        let child = self
12885            .parser
12886            .build_parse_trees
12887            .then(|| self.parser.terminal_tree(token));
12888        Ok((matched_eof, child))
12889    }
12890}
12891
12892impl<S, H> CommittedAtnParser<'_, '_, '_, S, H>
12893where
12894    S: TokenSource,
12895    H: SemanticHooks,
12896{
12897    fn parse_rule(
12898        &mut self,
12899        rule_index: usize,
12900        precedence: i32,
12901        inherited_local_int_arg: Option<(usize, i64)>,
12902        init_expected_state: Option<usize>,
12903    ) -> Result<CommittedRuleOutcome, AntlrError> {
12904        let start_state = self
12905            .atn
12906            .rule_to_start_state()
12907            .get(rule_index)
12908            .ok_or_else(|| {
12909                AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
12910            })?;
12911        let stop_state = self
12912            .atn
12913            .rule_to_stop_state()
12914            .get(rule_index)
12915            .filter(|state| *state != usize::MAX)
12916            .ok_or_else(|| {
12917                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
12918            })?;
12919        let left_recursive = self
12920            .atn
12921            .state(start_state)
12922            .is_some_and(AtnState::left_recursive_rule);
12923        if let Some(error) = self.parser.rule_depth_cap_violation() {
12924            return Err(error);
12925        }
12926        if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
12927            return Err(error);
12928        }
12929        let mut context = if left_recursive {
12930            self.parser.enter_recursion_rule(
12931                invoking_state_number(start_state),
12932                rule_index,
12933                precedence,
12934            )
12935        } else {
12936            self.parser
12937                .enter_rule(invoking_state_number(start_state), rule_index)
12938        };
12939        let rule_start_index = self.parser.current_visible_index();
12940        let local_int_arg =
12941            usize::try_from(context.invoking_state())
12942                .ok()
12943                .and_then(|source_state| {
12944                    rule_local_int_arg(
12945                        self.options.rule_args,
12946                        source_state,
12947                        rule_index,
12948                        inherited_local_int_arg,
12949                    )
12950                });
12951        if self.options.init_action_rules.contains(&rule_index) {
12952            let action = ParserAction::new_rule_init(
12953                rule_index,
12954                rule_start_index,
12955                init_expected_state.or(Some(start_state)),
12956            );
12957            if !self
12958                .parser
12959                .parser_rule_init_hook_with_context(action, &context, local_int_arg)
12960            {
12961                self.deferred_actions.push(action);
12962            }
12963        }
12964        let mut consumed_eof = false;
12965        let result = self.walk_rule(
12966            rule_index,
12967            start_state,
12968            stop_state,
12969            precedence,
12970            rule_start_index,
12971            local_int_arg,
12972            left_recursive,
12973            &mut context,
12974            &mut consumed_eof,
12975        );
12976
12977        let result = match result {
12978            Ok(()) => Ok(if left_recursive {
12979                self.parser.finish_recursion_rule(context, consumed_eof)
12980            } else {
12981                self.parser.finish_rule(context, consumed_eof)
12982            }),
12983            Err(error) if self.parser.bail_on_error() => {
12984                if left_recursive {
12985                    self.parser.unroll_recursion_context();
12986                } else {
12987                    self.parser.exit_rule();
12988                }
12989                Err(error)
12990            }
12991            Err(error) => {
12992                self.parser
12993                    .recover_generated_rule(&mut context, self.atn, error);
12994                Ok(if left_recursive {
12995                    self.parser.finish_recursion_rule(context, consumed_eof)
12996                } else {
12997                    self.parser.finish_rule(context, consumed_eof)
12998                })
12999            }
13000        };
13001        self.parser.parse_listener_exit_rule(rule_index);
13002        result.map(|tree| CommittedRuleOutcome { tree, consumed_eof })
13003    }
13004
13005    #[allow(clippy::too_many_arguments)]
13006    fn walk_rule(
13007        &mut self,
13008        rule_index: usize,
13009        mut state_number: usize,
13010        stop_state: usize,
13011        precedence: i32,
13012        rule_start_index: usize,
13013        local_int_arg: Option<(usize, i64)>,
13014        left_recursive: bool,
13015        context: &mut ParserRuleContext,
13016        consumed_eof: &mut bool,
13017    ) -> Result<(), AntlrError> {
13018        let mut entered_loops = BTreeSet::new();
13019        let mut visited_coordinates = FxHashSet::default();
13020        let mut guarded_input_index = self.parser.input.index();
13021        while state_number != stop_state {
13022            let input_index = self.parser.input.index();
13023            if input_index != guarded_input_index {
13024                visited_coordinates.clear();
13025                guarded_input_index = input_index;
13026            }
13027            if !visited_coordinates.insert((state_number, input_index)) {
13028                return Err(AntlrError::Unsupported(format!(
13029                    "committed parser encountered a non-consuming ATN cycle at state \
13030                         {state_number}"
13031                )));
13032            }
13033            let state = self.atn.state(state_number).ok_or_else(|| {
13034                AntlrError::Unsupported(format!("missing parser ATN state {state_number}"))
13035            })?;
13036            if state.is_rule_stop() {
13037                return Err(AntlrError::Unsupported(format!(
13038                    "rule {rule_index} reached unexpected stop state {state_number}"
13039                )));
13040            }
13041            let transition_index = {
13042                let mut decision_context = CommittedDecisionContext {
13043                    precedence,
13044                    local_int_arg,
13045                    context,
13046                    entered_loops: &mut entered_loops,
13047                };
13048                self.transition_index(state, &mut decision_context)?
13049            };
13050            let transition = state.transitions().get(transition_index).ok_or_else(|| {
13051                AntlrError::Unsupported(format!(
13052                    "missing transition {transition_index} from parser ATN state {state_number}"
13053                ))
13054            })?;
13055
13056            let next_alt = next_alt_number(
13057                state,
13058                state.transitions().len(),
13059                transition_index,
13060                context.alt_number(),
13061                self.options.track_alt_numbers,
13062            );
13063            if self.options.track_alt_numbers && context.alt_number() == 0 && next_alt != 0 {
13064                context.set_alt_number(next_alt);
13065            }
13066            let next_context_alt = next_alt_number(
13067                state,
13068                state.transitions().len(),
13069                transition_index,
13070                context.context_alt_number(),
13071                self.options.track_context_alt_numbers,
13072            );
13073            if self.options.track_context_alt_numbers
13074                && context.context_alt_number() == 0
13075                && next_context_alt != 0
13076            {
13077                context.set_context_alt_number(next_context_alt);
13078            }
13079
13080            if left_recursive
13081                && left_recursive_boundary(self.atn, state, transition.target()).is_some()
13082            {
13083                if let Some(error) = self.parser.rule_depth_cap_violation() {
13084                    return Err(error);
13085                }
13086                self.parser.parse_listener_exit_rule(rule_index);
13087                self.parser.push_new_recursion_context_with_previous(
13088                    invoking_state_number(
13089                        self.atn
13090                            .rule_to_start_state()
13091                            .get(rule_index)
13092                            .unwrap_or(state_number),
13093                    ),
13094                    rule_index,
13095                    context,
13096                );
13097                if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
13098                    return Err(error);
13099                }
13100            }
13101            state_number = self.apply_transition(
13102                state_number,
13103                transition,
13104                precedence,
13105                rule_start_index,
13106                local_int_arg,
13107                context,
13108                consumed_eof,
13109            )?;
13110        }
13111        Ok(())
13112    }
13113
13114    fn transition_index(
13115        &mut self,
13116        state: AtnState<'_>,
13117        decision_context: &mut CommittedDecisionContext<'_>,
13118    ) -> Result<usize, AntlrError> {
13119        let transition_count = state.transitions().len();
13120        if transition_count == 1 {
13121            return Ok(0);
13122        }
13123        let Some(decision) = self
13124            .decision_by_state
13125            .get(state.state_number())
13126            .copied()
13127            .flatten()
13128        else {
13129            return Err(AntlrError::Unsupported(format!(
13130                "parser ATN state {} has {transition_count} transitions but is not a decision",
13131                state.state_number()
13132            )));
13133        };
13134
13135        let decision_start = self.parser.input.index();
13136        let overridden_transition = if self.parser.semantic_hooks.observes_parser_decisions() {
13137            self.parser
13138                .semantic_hooks
13139                .parser_decision_override(decision, decision_start, transition_count)
13140                .and_then(|alternative| alternative.checked_sub(1))
13141                .filter(|alternative| *alternative < transition_count)
13142        } else {
13143            None
13144        };
13145        if let Some(selected) = overridden_transition {
13146            self.update_loop_selection(state, selected, decision_context);
13147            return Ok(selected);
13148        }
13149
13150        if !state.precedence_rule_decision() {
13151            let loop_back = match state.kind() {
13152                AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack => true,
13153                AtnStateKind::StarLoopEntry => decision_context
13154                    .entered_loops
13155                    .contains(&state.state_number()),
13156                _ => false,
13157            };
13158            let children = self.parser.sync_decision(
13159                self.atn,
13160                state.state_number(),
13161                !decision_context.context.has_matched_child(),
13162                loop_back,
13163            )?;
13164            for child in children {
13165                self.parser.add_parse_child(decision_context.context, child);
13166            }
13167        }
13168
13169        let prediction_precedence = if state.precedence_rule_decision() {
13170            usize::try_from(decision_context.precedence.max(0)).unwrap_or_default()
13171        } else {
13172            0
13173        };
13174        let prediction_context = {
13175            let return_states = self
13176                .parser
13177                .prediction_context_return_states(self.atn)
13178                .collect::<Vec<_>>();
13179            self.simulator
13180                .intern_prediction_context(self.parser.rule_context_version(), return_states)
13181        };
13182        self.simulator.set_exact_ambig_detection(
13183            self.parser.prediction_mode() == PredictionMode::LlExactAmbigDetection,
13184        );
13185        let prediction_mode = self.parser.prediction_mode();
13186        let prediction = match self.simulator.adaptive_predict_stream_info_sll_probe(
13187            decision,
13188            prediction_precedence,
13189            &mut self.parser.input,
13190        ) {
13191            Ok(prediction)
13192                if prediction.requires_full_context && prediction_mode != PredictionMode::Sll =>
13193            {
13194                self.simulator.adaptive_predict_stream_info_with_context(
13195                    decision,
13196                    prediction_precedence,
13197                    &mut self.parser.input,
13198                    prediction_context,
13199                )
13200            }
13201            prediction => prediction,
13202        };
13203        let mut prediction = match prediction {
13204            Ok(prediction) => prediction,
13205            Err(ParserAtnSimulatorError::NoViableAlt { index, .. })
13206                if state.precedence_rule_decision() =>
13207            {
13208                let enter_alt = state.transitions().iter().position(|transition| {
13209                    self.atn
13210                        .state(transition.target())
13211                        .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd)
13212                });
13213                let exit_alt = state.transitions().iter().position(|transition| {
13214                    self.atn
13215                        .state(transition.target())
13216                        .is_some_and(|target| target.kind() == AtnStateKind::LoopEnd)
13217                });
13218                let selected = if self.parser.left_recursive_loop_enter_matches(
13219                    self.atn,
13220                    state.state_number(),
13221                    decision_context.precedence,
13222                ) {
13223                    enter_alt
13224                } else {
13225                    exit_alt
13226                };
13227                let Some(selected) = selected else {
13228                    return Err(self
13229                        .parser
13230                        .no_viable_alternative_error_at(decision_start, index));
13231                };
13232                ParserAtnPrediction {
13233                    alt: selected + 1,
13234                    requires_full_context: true,
13235                    has_semantic_context: true,
13236                    diagnostic: None,
13237                }
13238            }
13239            Err(ParserAtnSimulatorError::NoViableAlt { index, .. }) => {
13240                return Err(self
13241                    .parser
13242                    .no_viable_alternative_error_at(decision_start, index));
13243            }
13244            Err(ParserAtnSimulatorError::PredictionRequiresMoreLookahead) => {
13245                return Err(self.parser.no_viable_alternative_error(decision_start));
13246            }
13247            Err(error) => {
13248                return Err(AntlrError::Unsupported(format!(
13249                    "committed parser prediction failed at decision {decision}: {error:?}"
13250                )));
13251            }
13252        };
13253        let mut selected = prediction
13254            .alt
13255            .checked_sub(1)
13256            .filter(|index| *index < transition_count)
13257            .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13258
13259        let semantic_candidates = self.simulator.prediction_semantic_candidates();
13260        if !semantic_candidates.is_empty() {
13261            let predicted_alt = prediction.alt;
13262            let mut semantic_results = BTreeMap::new();
13263            let selected_alt = selected + 1;
13264            let selected_matches = self.semantic_alternative_matches(
13265                selected_alt,
13266                decision_context,
13267                &semantic_candidates,
13268            );
13269            semantic_results.insert(selected_alt, selected_matches);
13270            if !selected_matches {
13271                let alternatives = semantic_candidates
13272                    .iter()
13273                    .map(|candidate| candidate.alt)
13274                    .filter(|alternative| *alternative != 0 && *alternative <= transition_count)
13275                    .collect::<BTreeSet<_>>();
13276                selected = alternatives
13277                    .into_iter()
13278                    .find(|alternative| {
13279                        let matches = self.semantic_alternative_matches(
13280                            *alternative,
13281                            decision_context,
13282                            &semantic_candidates,
13283                        );
13284                        semantic_results.insert(*alternative, matches);
13285                        matches
13286                    })
13287                    .and_then(|alternative| alternative.checked_sub(1))
13288                    .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13289            }
13290            if self.parser.report_diagnostic_errors
13291                && let Some(diagnostic) = prediction.diagnostic.as_ref()
13292            {
13293                for alternative in diagnostic.conflicting_alts.clone() {
13294                    if semantic_results.contains_key(&alternative)
13295                        || !semantic_candidates
13296                            .iter()
13297                            .any(|candidate| candidate.alt == alternative)
13298                    {
13299                        continue;
13300                    }
13301                    let matches = self.semantic_alternative_matches(
13302                        alternative,
13303                        decision_context,
13304                        &semantic_candidates,
13305                    );
13306                    semantic_results.insert(alternative, matches);
13307                }
13308            }
13309            Self::filter_prediction_diagnostic(
13310                &mut prediction,
13311                predicted_alt,
13312                selected + 1,
13313                &semantic_results,
13314            );
13315        }
13316        self.parser.record_generated_prediction_diagnostic(
13317            self.atn,
13318            state.state_number(),
13319            &prediction,
13320        );
13321
13322        self.update_loop_selection(state, selected, decision_context);
13323        Ok(selected)
13324    }
13325
13326    fn semantic_alternative_matches(
13327        &mut self,
13328        alternative: usize,
13329        decision_context: &CommittedDecisionContext<'_>,
13330        candidates: &[ParserSemanticCandidate],
13331    ) -> bool {
13332        candidates
13333            .iter()
13334            .filter(|candidate| candidate.alt == alternative)
13335            .any(|candidate| {
13336                self.semantic_context_matches(&candidate.context, decision_context, candidate)
13337            })
13338    }
13339
13340    fn filter_prediction_diagnostic(
13341        prediction: &mut ParserAtnPrediction,
13342        predicted_alt: usize,
13343        selected_alt: usize,
13344        semantic_results: &BTreeMap<usize, bool>,
13345    ) {
13346        prediction.alt = selected_alt;
13347        if selected_alt != predicted_alt {
13348            prediction.diagnostic = None;
13349            return;
13350        }
13351        if let Some(diagnostic) = prediction.diagnostic.as_mut() {
13352            diagnostic
13353                .conflicting_alts
13354                .retain(|alternative| semantic_results.get(alternative).copied().unwrap_or(true));
13355            if diagnostic.conflicting_alts.len() < 2 {
13356                prediction.diagnostic = None;
13357            }
13358        }
13359    }
13360
13361    fn semantic_context_matches(
13362        &mut self,
13363        semantic_context: &SemanticContext,
13364        decision_context: &CommittedDecisionContext<'_>,
13365        candidate: &ParserSemanticCandidate,
13366    ) -> bool {
13367        match semantic_context {
13368            SemanticContext::None => true,
13369            SemanticContext::Predicate {
13370                rule_index,
13371                pred_index,
13372                ..
13373            } => {
13374                let mut matched_provenance = false;
13375                for predicate_call in candidate
13376                    .predicate_calls
13377                    .iter()
13378                    .filter(|call| call.rule_index == *rule_index && call.pred_index == *pred_index)
13379                {
13380                    matched_provenance = true;
13381                    let mut local_int_arg = decision_context.local_int_arg;
13382                    for rule_call in &predicate_call.rule_calls {
13383                        local_int_arg = rule_local_int_arg(
13384                            self.options.rule_args,
13385                            rule_call.source_state,
13386                            rule_call.rule_index,
13387                            local_int_arg,
13388                        );
13389                    }
13390                    if !self.semantic_predicate_matches(
13391                        *rule_index,
13392                        *pred_index,
13393                        decision_context,
13394                        local_int_arg,
13395                    ) {
13396                        return false;
13397                    }
13398                }
13399                if matched_provenance {
13400                    true
13401                } else {
13402                    self.semantic_predicate_matches(
13403                        *rule_index,
13404                        *pred_index,
13405                        decision_context,
13406                        decision_context.local_int_arg,
13407                    )
13408                }
13409            }
13410            SemanticContext::Precedence { precedence } => {
13411                *precedence >= decision_context.precedence
13412            }
13413            SemanticContext::And(children) => {
13414                for child in children {
13415                    if !self.semantic_context_matches(child, decision_context, candidate) {
13416                        return false;
13417                    }
13418                }
13419                true
13420            }
13421            SemanticContext::Or(children) => {
13422                for child in children {
13423                    if self.semantic_context_matches(child, decision_context, candidate) {
13424                        return true;
13425                    }
13426                }
13427                false
13428            }
13429        }
13430    }
13431
13432    fn semantic_predicate_matches(
13433        &mut self,
13434        rule_index: usize,
13435        pred_index: usize,
13436        decision_context: &CommittedDecisionContext<'_>,
13437        local_int_arg: Option<(usize, i64)>,
13438    ) -> bool {
13439        let member_values = self.parser.int_members.clone();
13440        self.parser.parser_predicate_matches(PredicateEval {
13441            index: self.parser.input.index(),
13442            rule_index,
13443            pred_index,
13444            predicates: self.options.predicates,
13445            semantics: self.options.semantics,
13446            context: Some(&*decision_context.context),
13447            local_int_arg,
13448            member_values: &member_values,
13449        })
13450    }
13451
13452    fn update_loop_selection(
13453        &self,
13454        state: AtnState<'_>,
13455        selected: usize,
13456        decision_context: &mut CommittedDecisionContext<'_>,
13457    ) {
13458        if state.kind() == AtnStateKind::StarLoopEntry {
13459            let enters = self
13460                .atn
13461                .state(
13462                    state
13463                        .transitions()
13464                        .get(selected)
13465                        .expect("selected transition is in bounds")
13466                        .target(),
13467                )
13468                .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd);
13469            if enters {
13470                decision_context.entered_loops.insert(state.state_number());
13471            } else {
13472                decision_context.entered_loops.remove(&state.state_number());
13473            }
13474        }
13475    }
13476
13477    #[allow(clippy::too_many_arguments)]
13478    fn apply_transition(
13479        &mut self,
13480        source_state: usize,
13481        transition: ParserTransition<'_>,
13482        precedence: i32,
13483        rule_start_index: usize,
13484        local_int_arg: Option<(usize, i64)>,
13485        context: &mut ParserRuleContext,
13486        consumed_eof: &mut bool,
13487    ) -> Result<usize, AntlrError> {
13488        self.parser.set_state(invoking_state_number(source_state));
13489        match transition.data() {
13490            Transition::Epsilon { target } => Ok(target),
13491            Transition::Atom { target, label } => {
13492                let matched = self
13493                    .parser
13494                    .match_token_recovering(label, target, self.atn)?;
13495                *consumed_eof |= matched.consumed_eof();
13496                for child in matched.into_child_iter() {
13497                    self.parser.add_parse_child(context, child);
13498                }
13499                Ok(target)
13500            }
13501            Transition::Range {
13502                target,
13503                start,
13504                stop,
13505            } => {
13506                let matched =
13507                    self.parser
13508                        .match_set_recovering(&[(start, stop)], target, self.atn)?;
13509                *consumed_eof |= matched.consumed_eof();
13510                for child in matched.into_child_iter() {
13511                    self.parser.add_parse_child(context, child);
13512                }
13513                Ok(target)
13514            }
13515            Transition::Set { target, set } => {
13516                let matched = self
13517                    .parser
13518                    .match_token_set_recovering(set, target, self.atn)?;
13519                *consumed_eof |= matched.consumed_eof();
13520                for child in matched.into_child_iter() {
13521                    self.parser.add_parse_child(context, child);
13522                }
13523                Ok(target)
13524            }
13525            Transition::NotSet { target, set } => {
13526                let matched = self.parser.match_not_token_set_recovering(
13527                    set,
13528                    1,
13529                    self.atn.max_token_type(),
13530                    target,
13531                    self.atn,
13532                )?;
13533                *consumed_eof |= matched.consumed_eof();
13534                for child in matched.into_child_iter() {
13535                    self.parser.add_parse_child(context, child);
13536                }
13537                Ok(target)
13538            }
13539            Transition::Wildcard { target } => {
13540                let matched = self.parser.match_not_set_recovering(
13541                    &[],
13542                    1,
13543                    self.atn.max_token_type(),
13544                    target,
13545                    self.atn,
13546                )?;
13547                *consumed_eof |= matched.consumed_eof();
13548                for child in matched.into_child_iter() {
13549                    self.parser.add_parse_child(context, child);
13550                }
13551                Ok(target)
13552            }
13553            Transition::Rule {
13554                rule_index,
13555                follow_state,
13556                precedence: rule_precedence,
13557                ..
13558            } => {
13559                let marker = self
13560                    .parser
13561                    .push_invoking_state(invoking_state_number(source_state));
13562                let child = if self.parser.generated_rule_stack_check_due() {
13563                    grow_generated_rule_stack(|| {
13564                        self.parse_rule(
13565                            rule_index,
13566                            rule_precedence,
13567                            local_int_arg,
13568                            Some(follow_state),
13569                        )
13570                    })
13571                } else {
13572                    self.parse_rule(
13573                        rule_index,
13574                        rule_precedence,
13575                        local_int_arg,
13576                        Some(follow_state),
13577                    )
13578                };
13579                self.parser.discard_invoking_state(marker);
13580                let child = child?;
13581                *consumed_eof |= child.consumed_eof;
13582                self.parser.add_parse_child(context, child.tree);
13583                Ok(follow_state)
13584            }
13585            Transition::Predicate {
13586                target,
13587                rule_index,
13588                pred_index,
13589                ..
13590            } => {
13591                let member_values = self.parser.int_members.clone();
13592                if self.parser.parser_predicate_matches(PredicateEval {
13593                    index: self.parser.input.index(),
13594                    rule_index,
13595                    pred_index,
13596                    predicates: self.options.predicates,
13597                    semantics: self.options.semantics,
13598                    context: Some(context),
13599                    local_int_arg,
13600                    member_values: &member_values,
13601                }) {
13602                    return Ok(target);
13603                }
13604                if let Some(message) = self
13605                    .options
13606                    .semantics
13607                    .and_then(|semantics| {
13608                        self.parser.parser_semantic_ir_predicate_failure_message(
13609                            rule_index, pred_index, semantics,
13610                        )
13611                    })
13612                    .or_else(|| {
13613                        self.parser.parser_predicate_failure_message(
13614                            rule_index,
13615                            pred_index,
13616                            self.options.predicates,
13617                        )
13618                    })
13619                {
13620                    return Err(self
13621                        .parser
13622                        .failed_predicate_option_error(rule_index, message));
13623                }
13624                Err(self.parser.failed_predicate_error("semantic predicate"))
13625            }
13626            Transition::Action {
13627                target, rule_index, ..
13628            } => {
13629                self.apply_translated_actions(source_state, rule_index, context);
13630                if let Some(action_index) = self.action_index(source_state) {
13631                    let action = self.parser.parser_action_at_current_indexed(
13632                        source_state,
13633                        rule_index,
13634                        action_index,
13635                        rule_start_index,
13636                        *consumed_eof,
13637                    );
13638                    let _ = self.parser.parser_action_hook_inner(
13639                        action,
13640                        Some(context),
13641                        None,
13642                        local_int_arg,
13643                        true,
13644                    );
13645                }
13646                Ok(target)
13647            }
13648            Transition::Precedence {
13649                target,
13650                precedence: transition_precedence,
13651            } => {
13652                if transition_precedence >= precedence {
13653                    Ok(target)
13654                } else {
13655                    Err(self
13656                        .parser
13657                        .failed_predicate_error(format!("precpred(_ctx, {transition_precedence})")))
13658                }
13659            }
13660        }
13661    }
13662
13663    fn apply_translated_actions(
13664        &mut self,
13665        source_state: usize,
13666        rule_index: usize,
13667        context: &mut ParserRuleContext,
13668    ) {
13669        apply_member_actions(
13670            source_state,
13671            self.options.member_actions,
13672            self.options.semantics,
13673            &mut self.parser.int_members,
13674        );
13675        let return_values = return_values_after_action(
13676            source_state,
13677            rule_index,
13678            self.options.return_actions,
13679            self.options.semantics,
13680            &BTreeMap::new(),
13681        );
13682        for (name, value) in return_values {
13683            context.set_int_return(name, value);
13684        }
13685    }
13686
13687    fn action_index(&self, source_state: usize) -> Option<usize> {
13688        self.action_index_by_state.get(&source_state).copied()
13689    }
13690}
13691
13692/// Detects the loop edge where ANTLR would call `pushNewRecursionContext` for a
13693/// transformed left-recursive rule.
13694fn left_recursive_boundary(atn: &Atn, state: AtnState<'_>, target: usize) -> Option<usize> {
13695    if !state.precedence_rule_decision() {
13696        return None;
13697    }
13698    let target_state = atn.state(target)?;
13699    if target_state.kind() == AtnStateKind::LoopEnd {
13700        return None;
13701    }
13702    state.rule_index()
13703}
13704
13705/// Selects the first outer alternative observed for a rule path.
13706///
13707/// ANTLR's alt-numbered tree contexts store the rule alternative chosen at the
13708/// outer decision. The metadata recognizer only needs this when a generated
13709/// grammar opts into that target template; otherwise the value remains `0` and
13710/// parse-tree rendering is unchanged.
13711fn next_alt_number(
13712    state: AtnState<'_>,
13713    transition_count: usize,
13714    transition_index: usize,
13715    current_alt_number: usize,
13716    track_alt_numbers: bool,
13717) -> usize {
13718    if !track_alt_numbers || current_alt_number != 0 || transition_count <= 1 {
13719        return current_alt_number;
13720    }
13721    if matches!(
13722        state.kind(),
13723        AtnStateKind::Basic
13724            | AtnStateKind::BlockStart
13725            | AtnStateKind::PlusBlockStart
13726            | AtnStateKind::StarBlockStart
13727            | AtnStateKind::StarLoopEntry
13728    ) && !state.precedence_rule_decision()
13729    {
13730        return transition_index + 1;
13731    }
13732    current_alt_number
13733}
13734
13735/// Converts an ATN state number into the signed invoking-state slot used by
13736/// ANTLR parse-tree contexts, saturating only for impossible platform widths.
13737fn invoking_state_number(state_number: usize) -> isize {
13738    isize::try_from(state_number).unwrap_or(isize::MAX)
13739}
13740
13741const fn packed_i32(value: u32) -> i32 {
13742    i32::from_le_bytes(value.to_le_bytes())
13743}
13744
13745fn direct_precedence(precedence: i32) -> usize {
13746    usize::try_from(precedence.max(0)).unwrap_or_default()
13747}
13748
13749fn token_input_display(token: &impl Token) -> String {
13750    format!("'{}'", token.text().unwrap_or("<EOF>"))
13751}
13752
13753fn display_input_text(text: &str) -> String {
13754    let mut out = String::new();
13755    for ch in text.chars() {
13756        match ch {
13757            '\n' => out.push_str("\\n"),
13758            '\r' => out.push_str("\\r"),
13759            '\t' => out.push_str("\\t"),
13760            other => out.push(other),
13761        }
13762    }
13763    out
13764}
13765
13766fn diagnostic_for_token<T: Token>(token: Option<T>, message: String) -> ParserDiagnostic {
13767    let (line, column, offending) = token.map_or((0, 0, None), |token| {
13768        (token.line(), token.column(), Some(token.token_id()))
13769    });
13770    ParserDiagnostic {
13771        line,
13772        column,
13773        message,
13774        offending,
13775    }
13776}
13777
13778fn expected_symbols_display(symbols: &BTreeSet<i32>, vocabulary: &Vocabulary) -> String {
13779    expected_symbols_display_iter(symbols.iter().copied(), vocabulary)
13780}
13781
13782fn expected_symbols_display_iter(
13783    symbols: impl IntoIterator<Item = i32>,
13784    vocabulary: &Vocabulary,
13785) -> String {
13786    let items = symbols
13787        .into_iter()
13788        .map(|symbol| expected_symbol_display(symbol, vocabulary))
13789        .collect::<Vec<_>>();
13790    if let [single] = items.as_slice() {
13791        return single.clone();
13792    }
13793    format!("{{{}}}", items.join(", "))
13794}
13795
13796fn expected_symbol_display(symbol: i32, vocabulary: &Vocabulary) -> String {
13797    if symbol == TOKEN_EOF {
13798        return "<EOF>".to_owned();
13799    }
13800    vocabulary.display_name(symbol)
13801}
13802
13803fn caller_follow_token_info_for_stream<S: TokenSource>(
13804    input: &mut CommonTokenStream<S>,
13805    index: usize,
13806) -> (i32, bool, bool) {
13807    // Generated callers own statement separators; leave them available when
13808    // an interpreted child rule can either stop before or consume one.
13809    if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !input.is_filled() {
13810        input.fill();
13811    }
13812    let token_type = input.token_type_at_index(index);
13813    let visible_channel = input.channel();
13814    let token = input.get(index);
13815    let is_boundary = token
13816        .as_ref()
13817        .and_then(Token::text)
13818        .is_some_and(is_caller_follow_boundary_text);
13819    let is_boundary_gap = token.as_ref().is_some_and(|token| {
13820        token.channel() != visible_channel
13821            || is_caller_follow_boundary_gap_text(token.text_or_empty())
13822    });
13823    (token_type, is_boundary, is_boundary_gap)
13824}
13825
13826fn is_caller_follow_boundary_text(text: &str) -> bool {
13827    text.chars().any(|ch| ch == ';' || ch == '\n')
13828        && text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13829}
13830
13831fn is_caller_follow_boundary_gap_text(text: &str) -> bool {
13832    text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13833}
13834
13835/// Returns whether `state` belongs to an ANTLR-transformed left-recursive rule.
13836/// Inline insertion in those precedence loops can synthesize a missing operand
13837/// before an operator and then block the legitimate loop-exit path.
13838fn state_is_left_recursive_rule(atn: &Atn, state: AtnState<'_>) -> bool {
13839    let Some(rule_index) = state.rule_index() else {
13840        return false;
13841    };
13842    atn.rule_to_start_state()
13843        .get(rule_index)
13844        .and_then(|state_number| atn.state(state_number))
13845        .is_some_and(AtnState::left_recursive_rule)
13846}
13847
13848/// Picks the better of two `parse_atn_rule` passes (with and without the
13849/// FIRST-set prefilter). A clean outcome (no diagnostics) always wins over a
13850/// recovered one; among recovered outcomes the second pass is preferred
13851/// because the no-prefilter walk reaches ANTLR-style recovery inside child
13852/// rules. If both passes failed, the second pass's expected-token snapshot
13853/// is returned so the caller renders the same diagnostic ANTLR would.
13854fn select_better_top_outcome(
13855    first: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13856    second: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13857    arena: &RecognitionArena,
13858) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
13859    match (first, second) {
13860        (Ok(first), Ok(second)) => {
13861            if arena.diagnostics(first.0.diagnostics).next().is_none() {
13862                Ok(first)
13863            } else {
13864                Ok(second)
13865            }
13866        }
13867        (Ok(first), Err(_)) => Ok(first),
13868        (Err(_), Ok(second)) => Ok(second),
13869        (Err(_), Err(second_expected)) => Err(second_expected),
13870    }
13871}
13872
13873/// Chooses the outermost parse result that consumed the most input.
13874///
13875/// The recognizer intentionally keeps shorter endpoints available while walking
13876/// nested rule transitions so callers can satisfy following tokens such as
13877/// `expr 'and' expr`. Only the public rule entry commits to one endpoint.
13878fn select_best_fast_outcome(
13879    outcomes: impl Iterator<Item = FastRecognizeOutcome>,
13880    prediction_mode: PredictionMode,
13881    caller_follow: Option<&TokenBitSet>,
13882    mut token_info_at: impl FnMut(usize) -> (i32, bool, bool),
13883    arena: &RecognitionArena,
13884) -> Option<FastRecognizeOutcome> {
13885    let mut best = None;
13886    let mut best_caller_follow = None;
13887    for outcome in outcomes {
13888        if matches!(
13889            prediction_mode,
13890            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
13891        ) && outcome.diagnostics.is_empty()
13892            && let Some(follow) = caller_follow
13893        {
13894            let (token_type, is_boundary, _) = token_info_at(outcome.index);
13895            if is_boundary && follow.contains(token_type) {
13896                let replace =
13897                    best_caller_follow
13898                        .as_ref()
13899                        .is_none_or(|existing: &FastRecognizeOutcome| {
13900                            (outcome.index, outcome.consumed_eof)
13901                                < (existing.index, existing.consumed_eof)
13902                        });
13903                if replace {
13904                    best_caller_follow = Some(outcome);
13905                }
13906            }
13907        }
13908        let Some(existing) = best else {
13909            best = Some(outcome);
13910            continue;
13911        };
13912        let outcome_position = (outcome.index, outcome.consumed_eof);
13913        let best_position = (existing.index, existing.consumed_eof);
13914        let better = match prediction_mode {
13915            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => outcome_is_better(
13916                outcome_position,
13917                outcome.diagnostics,
13918                best_position,
13919                existing.diagnostics,
13920                arena,
13921            ),
13922            PredictionMode::Sll => outcome.index > existing.index,
13923        };
13924        best = Some(if better { outcome } else { existing });
13925    }
13926    let should_use_caller_follow =
13927        best_caller_follow
13928            .as_ref()
13929            .zip(best.as_ref())
13930            .is_some_and(|(candidate, selected)| {
13931                if !selected.diagnostics.is_empty() {
13932                    return true;
13933                }
13934                candidate.index < selected.index
13935                    && (candidate.index..selected.index).all(|index| token_info_at(index).2)
13936            });
13937    if should_use_caller_follow {
13938        best_caller_follow
13939    } else {
13940        best
13941    }
13942}
13943
13944fn select_best_outcome(
13945    outcomes: impl Iterator<Item = RecognizeOutcome>,
13946    prediction_mode: PredictionMode,
13947    arena: &RecognitionArena,
13948) -> Option<RecognizeOutcome> {
13949    let outcomes = outcomes.collect::<Vec<_>>();
13950    let prefer_first_tie = outcomes
13951        .iter()
13952        .any(|outcome| arena.sequence_needs_stable_tie(outcome.nodes));
13953    outcomes.into_iter().reduce(|best, outcome| {
13954        let outcome_position = (outcome.index, outcome.consumed_eof);
13955        let best_position = (best.index, best.consumed_eof);
13956        let better = match prediction_mode {
13957            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => {
13958                outcome_is_better(
13959                    outcome_position,
13960                    outcome.diagnostics,
13961                    best_position,
13962                    best.diagnostics,
13963                    arena,
13964                ) || (outcome_position == best_position
13965                    && arena.diagnostics_len(outcome.diagnostics)
13966                        == arena.diagnostics_len(best.diagnostics)
13967                    && arena.diagnostics_recovery_rank(outcome.diagnostics)
13968                        == arena.diagnostics_recovery_rank(best.diagnostics)
13969                    && (outcome.decisions < best.decisions
13970                        || (!prefer_first_tie
13971                            && outcome.decisions == best.decisions
13972                            && outcome.actions > best.actions)))
13973            }
13974            PredictionMode::Sll => {
13975                outcome_position > best_position
13976                    || (outcome_position == best_position
13977                        && !prefer_first_tie
13978                        && (outcome.decisions < best.decisions
13979                            || (outcome.decisions == best.decisions
13980                                && outcome_is_better(
13981                                    outcome_position,
13982                                    outcome.diagnostics,
13983                                    best_position,
13984                                    best.diagnostics,
13985                                    arena,
13986                                ))))
13987            }
13988        };
13989        if better {
13990            return outcome;
13991        }
13992        best
13993    })
13994}
13995
13996/// Records the serialized transition order at parser decision states.
13997///
13998/// When two clean paths consume the same input, ANTLR's adaptive prediction
13999/// chooses by alternative order. Keeping this compact trace lets the metadata
14000/// recognizer distinguish greedy and non-greedy optional blocks without a full
14001/// prediction simulator.
14002fn transition_decision(
14003    atn: &Atn,
14004    state: AtnState<'_>,
14005    transition_count: usize,
14006    transition_index: usize,
14007    predicates: &[(usize, usize, ParserPredicate)],
14008) -> Option<usize> {
14009    if transition_count <= 1 || decision_reaches_unsupported_predicate(atn, state, predicates) {
14010        return None;
14011    }
14012    Some(transition_index)
14013}
14014
14015/// Reports whether a state should reset the active no-viable decision start.
14016///
14017/// Loop entry/back states are continuations of the surrounding adaptive
14018/// prediction; resetting at those states would turn LL-star failures back into
14019/// ordinary mismatches.
14020fn starts_prediction_decision(state: AtnState<'_>, transition_count: usize) -> bool {
14021    transition_count > 1
14022        && !matches!(
14023            state.kind(),
14024            AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack | AtnStateKind::StarLoopEntry
14025        )
14026}
14027
14028/// Marks a farthest expected-token set as no-viable when multiple alternatives
14029/// failed after the active decision had already consumed input.
14030fn record_no_viable_if_ambiguous(
14031    expected: &mut ExpectedTokens,
14032    decision_start_index: Option<usize>,
14033    index: usize,
14034) {
14035    if expected.index == Some(index) && expected.symbols.len() > 1 {
14036        if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
14037            expected.record_no_viable(decision_start, index);
14038        }
14039    }
14040}
14041
14042/// Records a no-viable decision caused by a failed semantic predicate before
14043/// any consuming transition can contribute an expected-token set.
14044const fn record_predicate_no_viable(
14045    expected: &mut ExpectedTokens,
14046    decision_start_index: Option<usize>,
14047    index: usize,
14048) {
14049    if let Some(decision_start) = decision_start_index {
14050        expected.record_no_viable(decision_start, index);
14051    }
14052}
14053
14054/// Returns the active decision start only when the error is past that start.
14055const fn no_viable_decision_start(
14056    decision_start_index: Option<usize>,
14057    index: usize,
14058) -> Option<usize> {
14059    match decision_start_index {
14060        Some(start) if index > start => Some(start),
14061        _ => None,
14062    }
14063}
14064
14065/// Restores expected-token bookkeeping when a child rule found a clean
14066/// consuming path; failures in longer child alternatives should not pollute the
14067/// caller's final expectation set.
14068fn restore_expected(
14069    children: &[RecognizeOutcome],
14070    child_start_index: usize,
14071    expected: &mut ExpectedTokens,
14072    snapshot: ExpectedTokens,
14073    preserve_child_expected: bool,
14074) {
14075    if preserve_child_expected {
14076        return;
14077    }
14078    if children
14079        .iter()
14080        .any(|child| child.diagnostics.is_empty() && child.index > child_start_index)
14081    {
14082        *expected = snapshot;
14083    }
14084}
14085
14086/// Reports whether a decision can reach a predicate the generator did not
14087/// translate. Static alternative order is unsafe for those context predicates.
14088fn decision_reaches_unsupported_predicate(
14089    atn: &Atn,
14090    state: AtnState<'_>,
14091    predicates: &[(usize, usize, ParserPredicate)],
14092) -> bool {
14093    state.transitions().iter().any(|transition| {
14094        transition_reaches_unsupported_predicate(atn, transition, predicates, &mut BTreeSet::new())
14095    })
14096}
14097
14098/// Walks epsilon-like edges from one transition to find unsupported predicates.
14099fn transition_reaches_unsupported_predicate(
14100    atn: &Atn,
14101    transition: ParserTransition<'_>,
14102    predicates: &[(usize, usize, ParserPredicate)],
14103    visited: &mut BTreeSet<usize>,
14104) -> bool {
14105    match &transition.data() {
14106        Transition::Predicate {
14107            rule_index,
14108            pred_index,
14109            ..
14110        } => !predicates
14111            .iter()
14112            .any(|(rule, pred, _)| rule == rule_index && pred == pred_index),
14113        Transition::Epsilon { target }
14114        | Transition::Action { target, .. }
14115        | Transition::Rule { target, .. } => {
14116            state_reaches_unsupported_predicate(atn, *target, predicates, visited)
14117        }
14118        Transition::Precedence { .. }
14119        | Transition::Atom { .. }
14120        | Transition::Range { .. }
14121        | Transition::Set { .. }
14122        | Transition::NotSet { .. }
14123        | Transition::Wildcard { .. } => false,
14124    }
14125}
14126
14127/// Finds an unsupported predicate reachable before a consuming transition.
14128fn state_reaches_unsupported_predicate(
14129    atn: &Atn,
14130    state_number: usize,
14131    predicates: &[(usize, usize, ParserPredicate)],
14132    visited: &mut BTreeSet<usize>,
14133) -> bool {
14134    if !visited.insert(state_number) {
14135        return false;
14136    }
14137    let Some(state) = atn.state(state_number) else {
14138        return false;
14139    };
14140    state.transitions().iter().any(|transition| {
14141        transition_reaches_unsupported_predicate(atn, transition, predicates, visited)
14142    })
14143}
14144
14145/// Adds a decision step to the front of an already-recognized suffix path.
14146fn prepend_decision(outcome: &mut RecognizeOutcome, decision: Option<usize>) {
14147    if let Some(decision) = decision {
14148        outcome.decisions.insert(0, decision);
14149    }
14150}
14151
14152fn outcome_is_better(
14153    outcome_position: (usize, bool),
14154    outcome_diagnostics: DiagnosticSeqId,
14155    best_position: (usize, bool),
14156    best_diagnostics: DiagnosticSeqId,
14157    arena: &RecognitionArena,
14158) -> bool {
14159    let outcome_len = arena.diagnostics_len(outcome_diagnostics);
14160    let best_len = arena.diagnostics_len(best_diagnostics);
14161    outcome_position > best_position
14162        || (outcome_position == best_position
14163            && (outcome_len < best_len
14164                || (outcome_len == best_len
14165                    && arena.diagnostics_recovery_rank(outcome_diagnostics)
14166                        < arena.diagnostics_recovery_rank(best_diagnostics))))
14167}
14168
14169fn discard_recovered_fast_outcomes_if_clean_path_exists(outcomes: &mut Vec<FastRecognizeOutcome>) {
14170    if outcomes
14171        .iter()
14172        .any(|outcome| outcome.diagnostics.is_empty())
14173    {
14174        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14175    }
14176}
14177
14178fn discard_recovered_outcomes_if_clean_path_exists(
14179    outcomes: &mut Vec<RecognizeOutcome>,
14180    arena: &RecognitionArena,
14181) {
14182    if outcomes
14183        .iter()
14184        .any(|outcome| outcome_has_rule_failure_diagnostic(outcome, arena))
14185    {
14186        return;
14187    }
14188    if outcomes
14189        .iter()
14190        .any(|outcome| outcome.diagnostics.is_empty())
14191    {
14192        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14193    }
14194}
14195
14196/// Reports whether a recovered outcome came from an explicit predicate
14197/// fail-option and therefore should compete with shorter clean loop exits.
14198fn outcome_has_rule_failure_diagnostic(
14199    outcome: &RecognizeOutcome,
14200    arena: &RecognitionArena,
14201) -> bool {
14202    arena
14203        .diagnostics(outcome.diagnostics)
14204        .any(|diagnostic| diagnostic.message.starts_with("rule "))
14205}
14206
14207/// Removes equivalent endpoints before memoizing a state result while
14208/// preserving ATN transition-discovery order.
14209///
14210/// Outcomes are compared on observable recognition state — the input index,
14211/// EOF consumption, and diagnostics — without descending into the parse-tree
14212/// fragment carried by `nodes`. Two paths reaching the same point with
14213/// different node trees would otherwise prevent memoization from collapsing
14214/// equivalent suffixes and explode the speculative-path cache.
14215///
14216/// The first occurrence per recognition key wins, which matches ANTLR's
14217/// greedy alternative selection: serialized ATNs put greedy `*`/`+` loop-back
14218/// transitions before loop-exit, so the first-discovered outcome carries the
14219/// greedy parse-tree fragment.
14220fn dedupe_fast_outcomes(outcomes: &mut Vec<FastRecognizeOutcome>, arena: &RecognitionArena) {
14221    if outcomes.len() < 2 {
14222        return;
14223    }
14224    let mut seen = FxHashSet::with_capacity_and_hasher(outcomes.len(), FxBuildHasher::default());
14225    outcomes.retain(|outcome| {
14226        seen.insert((
14227            outcome.index,
14228            outcome.consumed_eof,
14229            arena.diagnostics_len(outcome.diagnostics),
14230            arena.diagnostics_recovery_rank(outcome.diagnostics),
14231        ))
14232    });
14233}
14234
14235const FAST_OUTCOME_INLINE_KEYS: usize = 8;
14236const FAST_OUTCOME_BITS_PER_WORD: usize = 64;
14237const MAX_FAST_OUTCOME_DENSE_BYTES: usize = 64 * 1024;
14238const MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS: usize = 65_536;
14239
14240#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14241enum FastOutcomeDedupStrategy {
14242    Inline,
14243    Dense,
14244    Sparse,
14245}
14246
14247impl FastOutcomeDedupScratch {
14248    fn prepare_dense(&mut self, word_count: usize) {
14249        while let Some(word_index) = self.touched_dense_words.pop() {
14250            self.dense_words[usize::try_from(word_index).expect("u32 fits in usize")] = 0;
14251        }
14252        if self.dense_words.len() < word_count {
14253            self.dense_words.resize(word_count, 0);
14254        }
14255    }
14256}
14257
14258fn clean_fast_outcome_dense_layout(outcomes: &[FastRecognizeOutcome]) -> Option<(usize, usize)> {
14259    let first_index = outcomes.first()?.index;
14260    let (min_index, max_index) = outcomes[1..].iter().fold(
14261        (first_index, first_index),
14262        |(min_index, max_index), outcome| {
14263            (min_index.min(outcome.index), max_index.max(outcome.index))
14264        },
14265    );
14266    let index_span = max_index.checked_sub(min_index)?.checked_add(1)?;
14267    let bit_count = index_span.checked_mul(2)?;
14268    let word_count =
14269        bit_count.checked_add(FAST_OUTCOME_BITS_PER_WORD - 1)? / FAST_OUTCOME_BITS_PER_WORD;
14270    let dense_bytes = word_count.checked_mul(size_of::<u64>())?;
14271    let sparse_key_bytes = outcomes.len().checked_mul(size_of::<(usize, bool)>())?;
14272    (dense_bytes <= MAX_FAST_OUTCOME_DENSE_BYTES && dense_bytes <= sparse_key_bytes)
14273        .then_some((min_index, word_count))
14274}
14275
14276#[cfg(feature = "perf-counters")]
14277fn record_clean_fast_outcome_dedup(
14278    strategy: FastOutcomeDedupStrategy,
14279    input_len: usize,
14280    output_len: usize,
14281    dense_words: usize,
14282) {
14283    let counter = match strategy {
14284        FastOutcomeDedupStrategy::Inline => &perf_counters::OUTCOME_DEDUPE_INLINE,
14285        FastOutcomeDedupStrategy::Dense => &perf_counters::OUTCOME_DEDUPE_DENSE,
14286        FastOutcomeDedupStrategy::Sparse => &perf_counters::OUTCOME_DEDUPE_SPARSE,
14287    };
14288    perf_counters::inc(
14289        &perf_counters::OUTCOME_DEDUPE_INPUTS,
14290        u64::try_from(input_len).unwrap_or(u64::MAX),
14291    );
14292    perf_counters::inc(
14293        &perf_counters::OUTCOME_DEDUPE_REMOVED,
14294        u64::try_from(input_len - output_len).unwrap_or(u64::MAX),
14295    );
14296    perf_counters::inc(counter, 1);
14297    perf_counters::inc(
14298        &perf_counters::OUTCOME_DEDUPE_DENSE_WORDS,
14299        u64::try_from(dense_words).unwrap_or(u64::MAX),
14300    );
14301}
14302
14303/// Removes duplicate clean endpoints while preserving transition-discovery
14304/// order. Tiny lists stay on the stack; larger compact ranges use a direct
14305/// bitmap, and only wide sparse ranges pay for hashing.
14306fn dedupe_clean_fast_outcomes(
14307    outcomes: &mut Vec<FastRecognizeOutcome>,
14308    scratch: &mut FastOutcomeDedupScratch,
14309) -> FastOutcomeDedupStrategy {
14310    #[cfg(feature = "perf-counters")]
14311    let input_len = outcomes.len();
14312    if outcomes.len() <= FAST_OUTCOME_INLINE_KEYS {
14313        let mut inline_keys = [(0, false); FAST_OUTCOME_INLINE_KEYS];
14314        let mut inline_len = 0_usize;
14315        outcomes.retain(|outcome| {
14316            let key = (outcome.index, outcome.consumed_eof);
14317            if inline_keys[..inline_len].contains(&key) {
14318                return false;
14319            }
14320            inline_keys[inline_len] = key;
14321            inline_len += 1;
14322            true
14323        });
14324        #[cfg(feature = "perf-counters")]
14325        record_clean_fast_outcome_dedup(
14326            FastOutcomeDedupStrategy::Inline,
14327            input_len,
14328            outcomes.len(),
14329            0,
14330        );
14331        return FastOutcomeDedupStrategy::Inline;
14332    }
14333
14334    if let Some((base_index, word_count)) = clean_fast_outcome_dense_layout(outcomes) {
14335        scratch.prepare_dense(word_count);
14336        outcomes.retain(|outcome| {
14337            let bit_index = (outcome.index - base_index) * 2 + usize::from(outcome.consumed_eof);
14338            let word_index = bit_index / FAST_OUTCOME_BITS_PER_WORD;
14339            let bit = 1_u64 << (bit_index % FAST_OUTCOME_BITS_PER_WORD);
14340            let word = &mut scratch.dense_words[word_index];
14341            if *word & bit != 0 {
14342                return false;
14343            }
14344            if *word == 0 {
14345                scratch
14346                    .touched_dense_words
14347                    .push(u32::try_from(word_index).expect("dense outcome bitmap is capped"));
14348            }
14349            *word |= bit;
14350            true
14351        });
14352        #[cfg(feature = "perf-counters")]
14353        record_clean_fast_outcome_dedup(
14354            FastOutcomeDedupStrategy::Dense,
14355            input_len,
14356            outcomes.len(),
14357            word_count,
14358        );
14359        return FastOutcomeDedupStrategy::Dense;
14360    }
14361
14362    scratch.sparse_keys.clear();
14363    scratch.sparse_keys.reserve(outcomes.len());
14364    outcomes.retain(|outcome| {
14365        scratch
14366            .sparse_keys
14367            .insert((outcome.index, outcome.consumed_eof))
14368    });
14369    #[cfg(feature = "perf-counters")]
14370    record_clean_fast_outcome_dedup(
14371        FastOutcomeDedupStrategy::Sparse,
14372        input_len,
14373        outcomes.len(),
14374        0,
14375    );
14376    if scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS {
14377        scratch.sparse_keys = FxHashSet::default();
14378    }
14379    FastOutcomeDedupStrategy::Sparse
14380}
14381
14382/// Sorts and removes equivalent endpoints, including action traces and the
14383/// arena-backed node sequence's structural contents.
14384fn dedupe_outcomes(outcomes: &mut Vec<RecognizeOutcome>, arena: &RecognitionArena) {
14385    outcomes.sort_unstable_by(|left, right| compare_recognize_outcomes(left, right, arena));
14386    outcomes
14387        .dedup_by(|left, right| compare_recognize_outcomes(left, right, arena) == Ordering::Equal);
14388}
14389
14390fn compare_recognize_outcomes(
14391    left: &RecognizeOutcome,
14392    right: &RecognizeOutcome,
14393    arena: &RecognitionArena,
14394) -> Ordering {
14395    left.index
14396        .cmp(&right.index)
14397        .then_with(|| left.consumed_eof.cmp(&right.consumed_eof))
14398        .then_with(|| left.alt_number.cmp(&right.alt_number))
14399        .then_with(|| left.member_values.cmp(&right.member_values))
14400        .then_with(|| left.return_values.cmp(&right.return_values))
14401        .then_with(|| arena.compare_diagnostics(left.diagnostics, right.diagnostics))
14402        .then_with(|| left.decisions.cmp(&right.decisions))
14403        .then_with(|| left.actions.cmp(&right.actions))
14404        .then_with(|| arena.compare_sequences(left.nodes, right.nodes))
14405}
14406
14407impl<S, H> Recognizer for BaseParser<S, H>
14408where
14409    S: TokenSource,
14410    H: SemanticHooks,
14411{
14412    fn data(&self) -> &RecognizerData {
14413        &self.data
14414    }
14415
14416    fn data_mut(&mut self) -> &mut RecognizerData {
14417        &mut self.data
14418    }
14419}
14420
14421impl<S, H> Parser for BaseParser<S, H>
14422where
14423    S: TokenSource,
14424    H: SemanticHooks,
14425{
14426    fn build_parse_trees(&self) -> bool {
14427        self.build_parse_trees
14428    }
14429
14430    fn set_build_parse_trees(&mut self, build: bool) {
14431        self.build_parse_trees = build;
14432    }
14433
14434    fn number_of_syntax_errors(&self) -> usize {
14435        Self::number_of_syntax_errors(self)
14436    }
14437
14438    fn report_diagnostic_errors(&self) -> bool {
14439        self.report_diagnostic_errors
14440    }
14441
14442    fn set_report_diagnostic_errors(&mut self, report: bool) {
14443        self.report_diagnostic_errors = report;
14444    }
14445
14446    fn prediction_mode(&self) -> PredictionMode {
14447        self.prediction_mode
14448    }
14449
14450    fn set_prediction_mode(&mut self, mode: PredictionMode) {
14451        self.prediction_mode = mode;
14452    }
14453
14454    fn max_rule_depth(&self) -> Option<usize> {
14455        self.max_rule_depth
14456    }
14457
14458    fn set_max_rule_depth(&mut self, depth: Option<usize>) {
14459        self.max_rule_depth = depth;
14460    }
14461
14462    fn add_parse_listener(&mut self, listener: Box<dyn ParseListener>) {
14463        self.parse_listeners.push(ParseListenerSlot(listener));
14464    }
14465
14466    fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
14467        Self::remove_parse_listeners(self)
14468    }
14469}
14470
14471#[cfg(test)]
14472#[allow(clippy::disallowed_methods)] // `insta` assertion macros unwrap internal I/O.
14473mod tests {
14474    use super::*;
14475    use crate::atn::parser::{
14476        ParserAtnPredictionDiagnostic, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
14477        context_containment_test_atn,
14478    };
14479    use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
14480    use crate::token::{HIDDEN_CHANNEL, Token, TokenId, TokenSink, TokenSpec, TokenStoreError};
14481    use crate::token_stream::CommonTokenStream;
14482    use crate::tree::{NodeKind, ParseTreeStats};
14483    use crate::vocabulary::Vocabulary;
14484    use std::cell::RefCell;
14485    use std::mem::size_of;
14486    use std::rc::Rc;
14487    use std::sync::{Arc, Mutex};
14488
14489    #[test]
14490    fn fx_hasher_write_matches_typed_methods_for_full_words() {
14491        // PR #5 review (Greptile P2): future key types whose `Hash` impl funnels
14492        // bytes through `Hasher::write` (e.g. `String`, `[u8; 8]`, slice-typed
14493        // fields) must hash the same as the typed methods, otherwise an
14494        // `FxHashMap` keyed on such a type silently disagrees with itself
14495        // depending on which entry point the caller used. Verify the
14496        // little-endian word equivalence this PR established.
14497        let value: u64 = 0x0102_0304_0506_0708;
14498        let mut typed = FxHasher::default();
14499        typed.write_u64(value);
14500        let mut bytewise = FxHasher::default();
14501        bytewise.write(&value.to_le_bytes());
14502        assert_eq!(typed.finish(), bytewise.finish());
14503    }
14504
14505    #[derive(Clone, Debug)]
14506    struct TestToken {
14507        spec: TokenSpec,
14508        id: TokenId,
14509        source_name: String,
14510    }
14511
14512    impl TestToken {
14513        fn new(token_type: i32) -> Self {
14514            Self {
14515                spec: TokenSpec::explicit(token_type, ""),
14516                id: TokenId::try_from(0).expect("zero token ID"),
14517                source_name: String::new(),
14518            }
14519        }
14520
14521        fn eof(source_name: &str, index: usize, line: usize, column: usize) -> Self {
14522            Self {
14523                spec: TokenSpec::eof(index, index, line, column),
14524                id: TokenId::try_from(0).expect("zero token ID"),
14525                source_name: source_name.to_owned(),
14526            }
14527        }
14528
14529        fn with_text(mut self, text: impl Into<String>) -> Self {
14530            self.spec.text = Some(text.into());
14531            self
14532        }
14533
14534        const fn with_channel(mut self, channel: i32) -> Self {
14535            self.spec.channel = channel;
14536            self
14537        }
14538
14539        fn with_span(mut self, start: usize, stop: usize) -> Self {
14540            self.spec = self.spec.with_span(start, stop);
14541            self
14542        }
14543
14544        fn with_byte_span(mut self, start: usize, stop: usize) -> Self {
14545            self.spec = self.spec.with_byte_span(start, stop);
14546            self
14547        }
14548
14549        const fn with_position(mut self, line: usize, column: usize) -> Self {
14550            self.spec.line = line;
14551            self.spec.column = column;
14552            self
14553        }
14554
14555        fn set_token_index(&mut self, index: isize) {
14556            self.id = TokenId::try_from(index.max(0).cast_unsigned()).expect("test token index");
14557        }
14558    }
14559
14560    impl Token for TestToken {
14561        fn token_id(&self) -> TokenId {
14562            self.id
14563        }
14564
14565        fn token_type(&self) -> i32 {
14566            self.spec.token_type
14567        }
14568
14569        fn channel(&self) -> i32 {
14570            self.spec.channel
14571        }
14572
14573        fn start(&self) -> usize {
14574            self.spec.start
14575        }
14576
14577        fn stop(&self) -> usize {
14578            self.spec.stop
14579        }
14580
14581        fn line(&self) -> usize {
14582            self.spec.line
14583        }
14584
14585        fn column(&self) -> usize {
14586            self.spec.column
14587        }
14588
14589        fn text(&self) -> Option<&str> {
14590            self.spec.text.as_deref()
14591        }
14592
14593        fn source_name(&self) -> &str {
14594            &self.source_name
14595        }
14596
14597        fn start_byte(&self) -> Option<usize> {
14598            (self.spec.start_byte != usize::MAX).then_some(self.spec.start_byte)
14599        }
14600
14601        fn stop_byte(&self) -> Option<usize> {
14602            (self.spec.stop_byte != usize::MAX).then_some(self.spec.stop_byte)
14603        }
14604    }
14605
14606    #[derive(Debug)]
14607    struct Source {
14608        tokens: Vec<TestToken>,
14609        index: usize,
14610    }
14611
14612    impl TokenSource for Source {
14613        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14614            let token = self
14615                .tokens
14616                .get(self.index)
14617                .cloned()
14618                .unwrap_or_else(|| TestToken::eof("parser-test", self.index, 1, self.index));
14619            self.index += 1;
14620            sink.push(token.spec)
14621        }
14622
14623        fn line(&self) -> usize {
14624            1
14625        }
14626
14627        fn column(&self) -> usize {
14628            self.index
14629        }
14630
14631        fn source_name(&self) -> &'static str {
14632            "parser-test"
14633        }
14634    }
14635
14636    #[derive(Clone, Debug, Eq, PartialEq)]
14637    struct RecordedDiagnostic {
14638        grammar_file_name: String,
14639        offending_text: Option<String>,
14640        line: usize,
14641        column: usize,
14642        span: Option<std::ops::Range<usize>>,
14643        message: String,
14644        error: Option<AntlrError>,
14645    }
14646
14647    #[derive(Clone, Debug)]
14648    struct RecordingErrorListener {
14649        diagnostics: Arc<Mutex<Vec<RecordedDiagnostic>>>,
14650    }
14651
14652    impl<R> crate::ErrorListener<R> for RecordingErrorListener
14653    where
14654        R: Recognizer + ?Sized,
14655    {
14656        fn syntax_error(&mut self, recognizer: &R, event: &SyntaxErrorEvent<'_>) {
14657            self.diagnostics
14658                .lock()
14659                .expect("recorded diagnostics lock")
14660                .push(RecordedDiagnostic {
14661                    grammar_file_name: recognizer.grammar_file_name().to_owned(),
14662                    offending_text: event
14663                        .offending
14664                        .and_then(|token| token.text().map(str::to_owned)),
14665                    line: event.line,
14666                    column: event.column,
14667                    span: event.span.clone(),
14668                    message: event.message.to_owned(),
14669                    error: event.error.cloned(),
14670                });
14671        }
14672    }
14673
14674    #[derive(Debug)]
14675    struct ReportingSource {
14676        source: Source,
14677        diagnostics: Rc<RefCell<Vec<TokenSourceError>>>,
14678    }
14679
14680    impl TokenSource for ReportingSource {
14681        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14682            self.source.next_token(sink)
14683        }
14684
14685        fn line(&self) -> usize {
14686            self.source.line()
14687        }
14688
14689        fn column(&self) -> usize {
14690            self.source.column()
14691        }
14692
14693        fn source_name(&self) -> &str {
14694            self.source.source_name()
14695        }
14696
14697        fn report_error(&self, error: &TokenSourceError) -> bool {
14698            self.diagnostics.borrow_mut().push(error.clone());
14699            true
14700        }
14701    }
14702
14703    fn mini_parser_data() -> RecognizerData {
14704        RecognizerData::new(
14705            "Mini.g4",
14706            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
14707        )
14708        .with_rule_names(["s"])
14709    }
14710
14711    fn mini_parser(tokens: Vec<TestToken>) -> BaseParser<Source> {
14712        let data = mini_parser_data();
14713        BaseParser::new(CommonTokenStream::new(Source { tokens, index: 0 }), data)
14714    }
14715
14716    fn mini_parser_with_hooks<H>(tokens: Vec<TestToken>, hooks: H) -> BaseParser<Source, H>
14717    where
14718        H: SemanticHooks,
14719    {
14720        BaseParser::with_semantic_hooks(
14721            CommonTokenStream::new(Source { tokens, index: 0 }),
14722            mini_parser_data(),
14723            hooks,
14724        )
14725    }
14726
14727    #[test]
14728    fn parser_dispatches_recovery_diagnostics_through_registered_listeners() {
14729        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
14730        parser.remove_error_listeners();
14731        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14732        parser.add_error_listener(RecordingErrorListener {
14733            diagnostics: Arc::clone(&diagnostics),
14734        });
14735        let parser_diagnostics = [ParserDiagnostic {
14736            line: 1,
14737            column: 2,
14738            message: "missing 'x' at 'y'".to_owned(),
14739            offending: None,
14740        }];
14741        let token_errors = [
14742            TokenSourceError::new(1, 1, "token recognition error at: '@'").with_span(1..2),
14743            TokenSourceError::new(1, 3, "token recognition error at: '#'").with_span(3..4),
14744        ];
14745
14746        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14747
14748        // The interleaved token/parser diagnostic stream (ordering, columns, messages) is one
14749        // reviewable snapshot instead of three hand-written RecordedDiagnostic literals.
14750        insta::assert_debug_snapshot!(
14751            "parser_dispatches_recovery_diagnostics_through_registered_listeners",
14752            *diagnostics.lock().expect("recorded diagnostics lock")
14753        );
14754
14755        parser.remove_error_listeners();
14756        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14757        assert_eq!(
14758            diagnostics.lock().expect("recorded diagnostics lock").len(),
14759            3
14760        );
14761    }
14762
14763    #[test]
14764    fn recovery_diagnostics_expose_the_offending_token_to_listeners() {
14765        let mut parser = mini_parser(vec![
14766            TestToken::new(7)
14767                .with_text("oops")
14768                .with_span(0, 3)
14769                .with_byte_span(0, 4)
14770                .with_position(1, 2),
14771            TestToken::eof("parser-test", 4, 1, 6),
14772        ]);
14773        parser.remove_error_listeners();
14774        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14775        parser.add_error_listener(RecordingErrorListener {
14776            diagnostics: Arc::clone(&diagnostics),
14777        });
14778        let offending = parser.input.lt_id(1);
14779        assert!(offending.is_some(), "current token should be buffered");
14780        let parser_diagnostics = [ParserDiagnostic {
14781            line: 1,
14782            column: 2,
14783            message: "extraneous input 'oops'".to_owned(),
14784            offending,
14785        }];
14786
14787        parser.dispatch_generated_diagnostics(&parser_diagnostics, &[]);
14788
14789        // Listeners receive a resolvable view of the offending token — the
14790        // ANTLR offendingSymbol contract downstream span-building error
14791        // reporters (miette-style byte-offset underlines) rely on.
14792        let recorded = diagnostics
14793            .lock()
14794            .expect("recorded diagnostics lock")
14795            .clone();
14796        insta::assert_debug_snapshot!(
14797            "recovery_diagnostics_expose_the_offending_token_to_listeners",
14798            recorded
14799        );
14800    }
14801
14802    #[test]
14803    fn recovery_diagnostics_preserve_unknown_custom_token_span() {
14804        let mut parser = mini_parser(vec![
14805            TestToken::new(7)
14806                .with_text("oops")
14807                .with_span(0, 3)
14808                .with_position(1, 2),
14809            TestToken::eof("parser-test", 4, 1, 6),
14810        ]);
14811        parser.remove_error_listeners();
14812        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14813        parser.add_error_listener(RecordingErrorListener {
14814            diagnostics: Arc::clone(&diagnostics),
14815        });
14816        let offending = parser.input.lt_id(1);
14817        assert!(offending.is_some(), "current token should be buffered");
14818
14819        parser.dispatch_parser_diagnostic(&ParserDiagnostic {
14820            line: 1,
14821            column: 2,
14822            message: "extraneous input 'oops'".to_owned(),
14823            offending,
14824        });
14825
14826        let span = {
14827            let diagnostics = diagnostics.lock().expect("recorded diagnostics lock");
14828            assert_eq!(diagnostics.len(), 1);
14829            diagnostics[0].span.clone()
14830        };
14831        assert_eq!(span, None);
14832    }
14833
14834    #[test]
14835    fn parser_leaves_token_errors_to_source_owned_listeners() {
14836        let source_diagnostics = Rc::new(RefCell::new(Vec::new()));
14837        let source = ReportingSource {
14838            source: Source {
14839                tokens: vec![TestToken::eof("parser-test", 0, 1, 0)],
14840                index: 0,
14841            },
14842            diagnostics: Rc::clone(&source_diagnostics),
14843        };
14844        let mut parser = BaseParser::new(CommonTokenStream::new(source), mini_parser_data());
14845        parser.remove_error_listeners();
14846        let parser_diagnostics = Arc::new(Mutex::new(Vec::new()));
14847        parser.add_error_listener(RecordingErrorListener {
14848            diagnostics: Arc::clone(&parser_diagnostics),
14849        });
14850        let source_error = TokenSourceError::new(2, 4, "token recognition error at: '$'");
14851
14852        parser.dispatch_token_source_errors(std::slice::from_ref(&source_error));
14853
14854        assert_eq!(*source_diagnostics.borrow(), [source_error]);
14855        assert!(
14856            parser_diagnostics
14857                .lock()
14858                .expect("recorded diagnostics lock")
14859                .is_empty()
14860        );
14861    }
14862
14863    fn finish_atn(builder: ParserAtnBuilder) -> Atn {
14864        builder.finish().expect("valid packed parser ATN")
14865    }
14866
14867    fn nested_rule_chain_atn(depth: usize) -> Atn {
14868        nested_rule_graph_atn(depth, false, false)
14869    }
14870
14871    fn nested_rule_graph_atn(depth: usize, branching: bool, consuming_follows: bool) -> Atn {
14872        assert!(depth > 0);
14873        let mut atn = ParserAtnBuilder::new(2);
14874        let mut starts = Vec::with_capacity(depth);
14875        let mut stops = Vec::with_capacity(depth);
14876        let mut follows = Vec::with_capacity(depth.saturating_sub(1));
14877        for rule_index in 0..depth {
14878            starts.push(
14879                atn.add_state(AtnStateKind::RuleStart, Some(rule_index))
14880                    .expect("rule start")
14881                    .index(),
14882            );
14883        }
14884        for rule_index in 0..depth {
14885            stops.push(
14886                atn.add_state(AtnStateKind::RuleStop, Some(rule_index))
14887                    .expect("rule stop")
14888                    .index(),
14889            );
14890        }
14891        if consuming_follows {
14892            for rule_index in 0..depth - 1 {
14893                follows.push(
14894                    atn.add_state(AtnStateKind::Basic, Some(rule_index))
14895                        .expect("rule follow")
14896                        .index(),
14897                );
14898            }
14899        }
14900        atn.set_rule_to_start_state(starts.clone())
14901            .expect("rule start states");
14902        atn.set_rule_to_stop_state(stops.clone())
14903            .expect("rule stop states");
14904        for rule_index in 0..depth - 1 {
14905            let follow_state = if consuming_follows {
14906                follows[rule_index]
14907            } else {
14908                stops[rule_index]
14909            };
14910            atn.add_transition(
14911                starts[rule_index],
14912                ParserTransitionSpec::Rule {
14913                    target: starts[rule_index + 1],
14914                    rule_index: rule_index + 1,
14915                    follow_state,
14916                    precedence: 0,
14917                },
14918            )
14919            .expect("nested rule transition");
14920            if branching {
14921                atn.add_transition(
14922                    starts[rule_index],
14923                    ParserTransitionSpec::Atom {
14924                        target: stops[rule_index],
14925                        label: 2,
14926                    },
14927                )
14928                .expect("dead branch transition");
14929            }
14930            if consuming_follows {
14931                atn.add_transition(
14932                    follow_state,
14933                    ParserTransitionSpec::Atom {
14934                        target: stops[rule_index],
14935                        label: 1,
14936                    },
14937                )
14938                .expect("consuming follow transition");
14939            }
14940        }
14941        let token_set = atn.add_interval_set([(1, 1)]).expect("token set");
14942        atn.add_transition(
14943            starts[depth - 1],
14944            ParserTransitionSpec::Set {
14945                target: stops[depth - 1],
14946                set: token_set,
14947            },
14948        )
14949        .expect("terminal set transition");
14950        if branching {
14951            atn.add_transition(
14952                starts[depth - 1],
14953                ParserTransitionSpec::Atom {
14954                    target: stops[depth - 1],
14955                    label: 2,
14956                },
14957            )
14958            .expect("dead leaf branch transition");
14959        }
14960        finish_atn(atn)
14961    }
14962
14963    fn ordinary_star_loop_atn() -> Atn {
14964        let mut atn = ParserAtnBuilder::new(2);
14965        for (state_number, kind, rule_index) in [
14966            (0, AtnStateKind::RuleStart, 0),
14967            (1, AtnStateKind::StarLoopEntry, 0),
14968            (2, AtnStateKind::Basic, 0),
14969            (3, AtnStateKind::StarLoopBack, 0),
14970            (4, AtnStateKind::LoopEnd, 0),
14971            (5, AtnStateKind::Basic, 0),
14972            (6, AtnStateKind::RuleStop, 0),
14973            (7, AtnStateKind::RuleStart, 1),
14974            (8, AtnStateKind::Basic, 1),
14975            (9, AtnStateKind::RuleStop, 1),
14976        ] {
14977            assert_eq!(
14978                atn.add_state(kind, Some(rule_index))
14979                    .expect("state")
14980                    .index(),
14981                state_number
14982            );
14983        }
14984        atn.set_rule_to_start_state(vec![0, 7])
14985            .expect("rule start states");
14986        atn.set_rule_to_stop_state(vec![6, 9])
14987            .expect("rule stop states");
14988        atn.add_decision_state(1).expect("decision state");
14989        atn.set_loop_back_state(4, 3).expect("loop back state");
14990        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14991            .expect("transition");
14992        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14993            .expect("transition");
14994        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
14995            .expect("transition");
14996        atn.add_transition(
14997            2,
14998            ParserTransitionSpec::Rule {
14999                target: 7,
15000                rule_index: 1,
15001                follow_state: 3,
15002                precedence: 0,
15003            },
15004        )
15005        .expect("transition");
15006        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 1 })
15007            .expect("transition");
15008        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15009            .expect("transition");
15010        atn.add_transition(
15011            5,
15012            ParserTransitionSpec::Atom {
15013                target: 6,
15014                label: TOKEN_EOF,
15015            },
15016        )
15017        .expect("transition");
15018        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
15019            .expect("transition");
15020        atn.add_transition(
15021            8,
15022            ParserTransitionSpec::Atom {
15023                target: 9,
15024                label: 1,
15025            },
15026        )
15027        .expect("transition");
15028        finish_atn(atn)
15029    }
15030
15031    /// ATN for `s : (X | X X)* EOF`.
15032    fn ambiguous_ordinary_star_loop_atn() -> Atn {
15033        let mut atn = ParserAtnBuilder::new(1);
15034        for (state_number, kind) in [
15035            (0, AtnStateKind::RuleStart),
15036            (1, AtnStateKind::StarLoopEntry),
15037            (2, AtnStateKind::StarBlockStart),
15038            (3, AtnStateKind::Basic),
15039            (4, AtnStateKind::BlockEnd),
15040            (5, AtnStateKind::StarLoopBack),
15041            (6, AtnStateKind::LoopEnd),
15042            (7, AtnStateKind::Basic),
15043            (8, AtnStateKind::RuleStop),
15044        ] {
15045            assert_eq!(
15046                atn.add_state(kind, Some(0)).expect("state").index(),
15047                state_number
15048            );
15049        }
15050        atn.set_rule_to_start_state(vec![0])
15051            .expect("rule start states");
15052        atn.set_rule_to_stop_state(vec![8])
15053            .expect("rule stop states");
15054        atn.set_end_state(2, 4).expect("block end state");
15055        atn.set_loop_back_state(6, 5).expect("loop back state");
15056        atn.add_decision_state(1).expect("decision state");
15057        atn.add_decision_state(2).expect("decision state");
15058        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15059            .expect("transition");
15060        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15061            .expect("transition");
15062        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
15063            .expect("transition");
15064        atn.add_transition(
15065            2,
15066            ParserTransitionSpec::Atom {
15067                target: 4,
15068                label: 1,
15069            },
15070        )
15071        .expect("transition");
15072        atn.add_transition(
15073            2,
15074            ParserTransitionSpec::Atom {
15075                target: 3,
15076                label: 1,
15077            },
15078        )
15079        .expect("transition");
15080        atn.add_transition(
15081            3,
15082            ParserTransitionSpec::Atom {
15083                target: 4,
15084                label: 1,
15085            },
15086        )
15087        .expect("transition");
15088        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15089            .expect("transition");
15090        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 1 })
15091            .expect("transition");
15092        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15093            .expect("transition");
15094        atn.add_transition(
15095            7,
15096            ParserTransitionSpec::Atom {
15097                target: 8,
15098                label: TOKEN_EOF,
15099            },
15100        )
15101        .expect("transition");
15102        finish_atn(atn)
15103    }
15104
15105    fn ordinary_plus_loop_atn() -> Atn {
15106        let mut atn = ParserAtnBuilder::new(2);
15107        for (state_number, kind, rule_index) in [
15108            (0, AtnStateKind::RuleStart, 0),
15109            (1, AtnStateKind::Basic, 0),
15110            (2, AtnStateKind::PlusLoopBack, 0),
15111            (3, AtnStateKind::LoopEnd, 0),
15112            (4, AtnStateKind::Basic, 0),
15113            (5, AtnStateKind::RuleStop, 0),
15114            (6, AtnStateKind::RuleStart, 1),
15115            (7, AtnStateKind::Basic, 1),
15116            (8, AtnStateKind::RuleStop, 1),
15117        ] {
15118            assert_eq!(
15119                atn.add_state(kind, Some(rule_index))
15120                    .expect("state")
15121                    .index(),
15122                state_number
15123            );
15124        }
15125        atn.set_rule_to_start_state(vec![0, 6])
15126            .expect("rule start states");
15127        atn.set_rule_to_stop_state(vec![5, 8])
15128            .expect("rule stop states");
15129        atn.add_decision_state(2).expect("decision state");
15130        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15131            .expect("transition");
15132        atn.add_transition(
15133            1,
15134            ParserTransitionSpec::Rule {
15135                target: 6,
15136                rule_index: 1,
15137                follow_state: 2,
15138                precedence: 0,
15139            },
15140        )
15141        .expect("transition");
15142        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 1 })
15143            .expect("transition");
15144        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15145            .expect("transition");
15146        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
15147            .expect("transition");
15148        atn.add_transition(
15149            4,
15150            ParserTransitionSpec::Atom {
15151                target: 5,
15152                label: TOKEN_EOF,
15153            },
15154        )
15155        .expect("transition");
15156        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15157            .expect("transition");
15158        atn.add_transition(
15159            7,
15160            ParserTransitionSpec::Atom {
15161                target: 8,
15162                label: 1,
15163            },
15164        )
15165        .expect("transition");
15166        finish_atn(atn)
15167    }
15168
15169    fn repeated_x_tokens(count: usize) -> Vec<TestToken> {
15170        let mut tokens = (0..count)
15171            .map(|_| TestToken::new(1).with_text("x"))
15172            .collect::<Vec<_>>();
15173        tokens.push(TestToken::eof("parser-test", count, 1, count));
15174        tokens
15175    }
15176
15177    fn left_recursive_loop_with_caller_follow_atn(caller_symbol: i32) -> Atn {
15178        let mut atn = ParserAtnBuilder::new(2);
15179        assert_eq!(
15180            atn.add_state(AtnStateKind::RuleStart, Some(0))
15181                .expect("state")
15182                .index(),
15183            0
15184        );
15185        assert_eq!(
15186            atn.add_state(AtnStateKind::Basic, Some(0))
15187                .expect("state")
15188                .index(),
15189            1
15190        );
15191        assert_eq!(
15192            atn.add_state(AtnStateKind::Basic, Some(0))
15193                .expect("state")
15194                .index(),
15195            2
15196        );
15197        assert_eq!(
15198            atn.add_state(AtnStateKind::RuleStart, Some(1))
15199                .expect("state")
15200                .index(),
15201            3
15202        );
15203        atn.set_left_recursive_rule(3)
15204            .expect("left-recursive rule start");
15205        assert_eq!(
15206            atn.add_state(AtnStateKind::StarLoopEntry, Some(1))
15207                .expect("state")
15208                .index(),
15209            4
15210        );
15211        atn.set_precedence_rule_decision(4)
15212            .expect("precedence decision");
15213        assert_eq!(
15214            atn.add_state(AtnStateKind::Basic, Some(1))
15215                .expect("state")
15216                .index(),
15217            5
15218        );
15219        assert_eq!(
15220            atn.add_state(AtnStateKind::Basic, Some(1))
15221                .expect("state")
15222                .index(),
15223            6
15224        );
15225        assert_eq!(
15226            atn.add_state(AtnStateKind::LoopEnd, Some(1))
15227                .expect("state")
15228                .index(),
15229            7
15230        );
15231        assert_eq!(
15232            atn.add_state(AtnStateKind::RuleStop, Some(1))
15233                .expect("state")
15234                .index(),
15235            8
15236        );
15237        assert_eq!(
15238            atn.add_state(AtnStateKind::RuleStop, Some(0))
15239                .expect("state")
15240                .index(),
15241            9
15242        );
15243        atn.set_rule_to_start_state(vec![0, 3])
15244            .expect("rule start states");
15245        atn.set_rule_to_stop_state(vec![9, 8])
15246            .expect("rule stop states");
15247        atn.add_transition(
15248            1,
15249            ParserTransitionSpec::Rule {
15250                target: 3,
15251                rule_index: 1,
15252                follow_state: 2,
15253                precedence: 0,
15254            },
15255        )
15256        .expect("transition");
15257        atn.add_transition(
15258            2,
15259            ParserTransitionSpec::Atom {
15260                target: 9,
15261                label: caller_symbol,
15262            },
15263        )
15264        .expect("transition");
15265        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15266            .expect("transition");
15267        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 7 })
15268            .expect("transition");
15269        atn.add_transition(
15270            5,
15271            ParserTransitionSpec::Precedence {
15272                target: 6,
15273                precedence: 1,
15274            },
15275        )
15276        .expect("transition");
15277        atn.add_transition(
15278            6,
15279            ParserTransitionSpec::Atom {
15280                target: 4,
15281                label: 1,
15282            },
15283        )
15284        .expect("transition");
15285        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
15286            .expect("transition");
15287        finish_atn(atn)
15288    }
15289
15290    fn labeled_left_recursive_operator_atn() -> Atn {
15291        let mut atn = ParserAtnBuilder::new(4);
15292        for (state, kind) in [
15293            (0, AtnStateKind::RuleStart),
15294            (1, AtnStateKind::BlockStart),
15295            (2, AtnStateKind::StarLoopEntry),
15296            (3, AtnStateKind::StarBlockStart),
15297            (4, AtnStateKind::Basic),
15298            (5, AtnStateKind::Basic),
15299            (6, AtnStateKind::Basic),
15300            (7, AtnStateKind::StarLoopBack),
15301            (8, AtnStateKind::LoopEnd),
15302            (9, AtnStateKind::RuleStop),
15303        ] {
15304            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15305        }
15306        atn.set_left_recursive_rule(0)
15307            .expect("left-recursive rule start");
15308        atn.set_precedence_rule_decision(2)
15309            .expect("precedence decision");
15310        atn.set_loop_back_state(8, 7).expect("loop-back state");
15311        atn.set_rule_to_start_state(vec![0])
15312            .expect("rule start states");
15313        atn.set_rule_to_stop_state(vec![9])
15314            .expect("rule stop states");
15315        for state in [1, 2, 3] {
15316            atn.add_decision_state(state).expect("decision state");
15317        }
15318        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
15319            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
15320                .expect("epsilon transition");
15321        }
15322        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3), (6, 7, 1)] {
15323            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
15324                .expect("token transition");
15325        }
15326        for (target, precedence) in [(4, 2), (5, 1)] {
15327            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
15328                .expect("operator precedence");
15329        }
15330        finish_atn(atn)
15331    }
15332
15333    fn parser_inside_left_recursive_callee(symbol: i32) -> BaseParser<Source> {
15334        let mut parser = mini_parser(vec![
15335            TestToken::new(symbol).with_text("lookahead"),
15336            TestToken::eof("parser-test", 1, 1, 1),
15337        ]);
15338        parser.rule_context_stack = vec![
15339            RuleContextFrame {
15340                rule_index: 0,
15341                invoking_state: -1,
15342            },
15343            RuleContextFrame {
15344                rule_index: 1,
15345                invoking_state: 1,
15346            },
15347        ];
15348        parser
15349    }
15350
15351    fn left_recursive_loop_with_shared_gt_prefix_atn() -> Atn {
15352        // StarLoopEntry with two operator alts that share leading token 1 (`>`):
15353        //   prec 2: token 1, token 1  (shift `>>`)
15354        //   prec 1: token 1           (relational `>`)
15355        let mut atn = ParserAtnBuilder::new(1);
15356        for (state, kind, rule) in [
15357            (0, AtnStateKind::RuleStart, 0),
15358            (1, AtnStateKind::StarLoopEntry, 0),
15359            (2, AtnStateKind::Basic, 0), // ops hub
15360            (3, AtnStateKind::Basic, 0), // shift prec
15361            (4, AtnStateKind::Basic, 0), // shift first >
15362            (5, AtnStateKind::Basic, 0), // shift second >
15363            (6, AtnStateKind::Basic, 0), // rel prec
15364            (7, AtnStateKind::Basic, 0), // rel >
15365            (8, AtnStateKind::LoopEnd, 0),
15366            (9, AtnStateKind::RuleStop, 0),
15367        ] {
15368            assert_eq!(
15369                atn.add_state(kind, Some(rule)).expect("state").index(),
15370                state
15371            );
15372            if state == 0 {
15373                atn.set_left_recursive_rule(state)
15374                    .expect("left-recursive rule start");
15375            } else if state == 1 {
15376                atn.set_precedence_rule_decision(state)
15377                    .expect("precedence decision");
15378            }
15379        }
15380        atn.set_rule_to_start_state(vec![0])
15381            .expect("rule start states");
15382        atn.set_rule_to_stop_state(vec![9])
15383            .expect("rule stop states");
15384        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15385            .expect("ops");
15386        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15387            .expect("exit");
15388        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15389            .expect("to shift");
15390        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15391            .expect("to rel");
15392        atn.add_transition(
15393            3,
15394            ParserTransitionSpec::Precedence {
15395                target: 4,
15396                precedence: 2,
15397            },
15398        )
15399        .expect("shift prec");
15400        atn.add_transition(
15401            4,
15402            ParserTransitionSpec::Atom {
15403                target: 5,
15404                label: 1,
15405            },
15406        )
15407        .expect("shift first >");
15408        atn.add_transition(
15409            5,
15410            ParserTransitionSpec::Atom {
15411                target: 1,
15412                label: 1,
15413            },
15414        )
15415        .expect("shift second >");
15416        atn.add_transition(
15417            6,
15418            ParserTransitionSpec::Precedence {
15419                target: 7,
15420                precedence: 1,
15421            },
15422        )
15423        .expect("rel prec");
15424        atn.add_transition(
15425            7,
15426            ParserTransitionSpec::Atom {
15427                target: 1,
15428                label: 1,
15429            },
15430        )
15431        .expect("rel >");
15432        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15433            .expect("loop end");
15434        finish_atn(atn)
15435    }
15436
15437    fn left_recursive_loop_with_rule_wrapped_gt_prefix_atn() -> Atn {
15438        let mut atn = ParserAtnBuilder::new(2);
15439        for (state, kind, rule) in [
15440            (0, AtnStateKind::RuleStart, 0),
15441            (1, AtnStateKind::StarLoopEntry, 0),
15442            (2, AtnStateKind::Basic, 0),
15443            (3, AtnStateKind::Basic, 0),
15444            (4, AtnStateKind::Basic, 0),
15445            (5, AtnStateKind::Basic, 0),
15446            (6, AtnStateKind::Basic, 0),
15447            (7, AtnStateKind::Basic, 0),
15448            (8, AtnStateKind::LoopEnd, 0),
15449            (9, AtnStateKind::RuleStop, 0),
15450            (10, AtnStateKind::RuleStart, 1),
15451            (11, AtnStateKind::Basic, 1),
15452            (12, AtnStateKind::RuleStop, 1),
15453        ] {
15454            assert_eq!(
15455                atn.add_state(kind, Some(rule)).expect("state").index(),
15456                state
15457            );
15458            if state == 0 {
15459                atn.set_left_recursive_rule(state)
15460                    .expect("left-recursive rule start");
15461            } else if state == 1 {
15462                atn.set_precedence_rule_decision(state)
15463                    .expect("precedence decision");
15464            }
15465        }
15466        atn.set_rule_to_start_state(vec![0, 10])
15467            .expect("rule start states");
15468        atn.set_rule_to_stop_state(vec![9, 12])
15469            .expect("rule stop states");
15470        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15471            .expect("ops");
15472        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15473            .expect("exit");
15474        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15475            .expect("to shift");
15476        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15477            .expect("to relational");
15478        atn.add_transition(
15479            3,
15480            ParserTransitionSpec::Precedence {
15481                target: 4,
15482                precedence: 2,
15483            },
15484        )
15485        .expect("shift precedence");
15486        atn.add_transition(
15487            4,
15488            ParserTransitionSpec::Rule {
15489                target: 10,
15490                rule_index: 1,
15491                follow_state: 5,
15492                precedence: 0,
15493            },
15494        )
15495        .expect("first shift token helper");
15496        atn.add_transition(
15497            5,
15498            ParserTransitionSpec::Atom {
15499                target: 1,
15500                label: 1,
15501            },
15502        )
15503        .expect("second shift token");
15504        atn.add_transition(
15505            6,
15506            ParserTransitionSpec::Precedence {
15507                target: 7,
15508                precedence: 1,
15509            },
15510        )
15511        .expect("relational precedence");
15512        atn.add_transition(
15513            7,
15514            ParserTransitionSpec::Atom {
15515                target: 1,
15516                label: 1,
15517            },
15518        )
15519        .expect("relational token");
15520        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15521            .expect("loop end");
15522        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
15523            .expect("helper entry");
15524        atn.add_transition(
15525            11,
15526            ParserTransitionSpec::Atom {
15527                target: 12,
15528                label: 1,
15529            },
15530        )
15531        .expect("first shift token");
15532        finish_atn(atn)
15533    }
15534
15535    fn left_recursive_loop_with_predicate_and_multi_token_prefix_atn() -> Atn {
15536        let mut atn = ParserAtnBuilder::new(1);
15537        for (state, kind) in [
15538            (0, AtnStateKind::RuleStart),
15539            (1, AtnStateKind::StarLoopEntry),
15540            (2, AtnStateKind::Basic),
15541            (3, AtnStateKind::Basic),
15542            (4, AtnStateKind::Basic),
15543            (5, AtnStateKind::Basic),
15544            (6, AtnStateKind::Basic),
15545            (7, AtnStateKind::Basic),
15546            (8, AtnStateKind::Basic),
15547            (9, AtnStateKind::LoopEnd),
15548            (10, AtnStateKind::RuleStop),
15549        ] {
15550            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15551            if state == 0 {
15552                atn.set_left_recursive_rule(state)
15553                    .expect("left-recursive rule start");
15554            } else if state == 1 {
15555                atn.set_precedence_rule_decision(state)
15556                    .expect("precedence decision");
15557            }
15558        }
15559        atn.set_rule_to_start_state(vec![0])
15560            .expect("rule start states");
15561        atn.set_rule_to_stop_state(vec![10])
15562            .expect("rule stop states");
15563        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15564            .expect("ops");
15565        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 9 })
15566            .expect("exit");
15567        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15568            .expect("to multi-token operator");
15569        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15570            .expect("to predicate operator");
15571        atn.add_transition(
15572            3,
15573            ParserTransitionSpec::Precedence {
15574                target: 4,
15575                precedence: 2,
15576            },
15577        )
15578        .expect("multi-token precedence");
15579        atn.add_transition(
15580            4,
15581            ParserTransitionSpec::Atom {
15582                target: 5,
15583                label: 1,
15584            },
15585        )
15586        .expect("multi-token first");
15587        atn.add_transition(
15588            5,
15589            ParserTransitionSpec::Atom {
15590                target: 1,
15591                label: 1,
15592            },
15593        )
15594        .expect("multi-token second");
15595        atn.add_transition(
15596            6,
15597            ParserTransitionSpec::Precedence {
15598                target: 7,
15599                precedence: 2,
15600            },
15601        )
15602        .expect("predicate precedence");
15603        atn.add_transition(
15604            7,
15605            ParserTransitionSpec::Predicate {
15606                target: 8,
15607                rule_index: 0,
15608                pred_index: 0,
15609                context_dependent: false,
15610            },
15611        )
15612        .expect("operator predicate");
15613        atn.add_transition(
15614            8,
15615            ParserTransitionSpec::Atom {
15616                target: 1,
15617                label: 1,
15618            },
15619        )
15620        .expect("predicate single token");
15621        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15622            .expect("loop end");
15623        finish_atn(atn)
15624    }
15625
15626    fn left_recursive_loop_with_nullable_operator_prefix_atn() -> Atn {
15627        let mut atn = ParserAtnBuilder::new(2);
15628        for (state, kind, rule) in [
15629            (0, AtnStateKind::RuleStart, 0),
15630            (1, AtnStateKind::StarLoopEntry, 0),
15631            (2, AtnStateKind::Basic, 0),
15632            (3, AtnStateKind::Basic, 0),
15633            (4, AtnStateKind::Basic, 0),
15634            (5, AtnStateKind::LoopEnd, 0),
15635            (6, AtnStateKind::RuleStop, 0),
15636            (7, AtnStateKind::RuleStart, 1),
15637            (8, AtnStateKind::RuleStop, 1),
15638            (9, AtnStateKind::Basic, 1),
15639        ] {
15640            assert_eq!(
15641                atn.add_state(kind, Some(rule)).expect("state").index(),
15642                state
15643            );
15644            if state == 0 {
15645                atn.set_left_recursive_rule(state)
15646                    .expect("left-recursive rule start");
15647            } else if state == 1 {
15648                atn.set_precedence_rule_decision(state)
15649                    .expect("precedence decision");
15650            }
15651        }
15652        atn.set_rule_to_start_state(vec![0, 7])
15653            .expect("rule start states");
15654        atn.set_rule_to_stop_state(vec![6, 8])
15655            .expect("rule stop states");
15656        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15657            .expect("transition");
15658        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15659            .expect("transition");
15660        atn.add_transition(
15661            2,
15662            ParserTransitionSpec::Precedence {
15663                target: 3,
15664                precedence: 3,
15665            },
15666        )
15667        .expect("transition");
15668        atn.add_transition(
15669            3,
15670            ParserTransitionSpec::Rule {
15671                target: 7,
15672                rule_index: 1,
15673                follow_state: 4,
15674                precedence: 0,
15675            },
15676        )
15677        .expect("transition");
15678        atn.add_transition(
15679            4,
15680            ParserTransitionSpec::Atom {
15681                target: 1,
15682                label: 1,
15683            },
15684        )
15685        .expect("transition");
15686        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15687            .expect("transition");
15688        atn.add_transition(
15689            7,
15690            ParserTransitionSpec::Precedence {
15691                target: 9,
15692                precedence: 1,
15693            },
15694        )
15695        .expect("transition");
15696        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 8 })
15697            .expect("transition");
15698        finish_atn(atn)
15699    }
15700
15701    fn left_recursive_loop_with_predicate_guarded_operator_atn() -> Atn {
15702        let mut atn = ParserAtnBuilder::new(2);
15703        for (state, kind) in [
15704            (0, AtnStateKind::RuleStart),
15705            (1, AtnStateKind::StarLoopEntry),
15706            (2, AtnStateKind::Basic),
15707            (3, AtnStateKind::Basic),
15708            (4, AtnStateKind::Basic),
15709            (5, AtnStateKind::LoopEnd),
15710            (6, AtnStateKind::RuleStop),
15711        ] {
15712            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15713            if state == 0 {
15714                atn.set_left_recursive_rule(state)
15715                    .expect("left-recursive rule start");
15716            } else if state == 1 {
15717                atn.set_precedence_rule_decision(state)
15718                    .expect("precedence decision");
15719            }
15720        }
15721        atn.set_rule_to_start_state(vec![0])
15722            .expect("rule start states");
15723        atn.set_rule_to_stop_state(vec![6])
15724            .expect("rule stop states");
15725        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15726            .expect("transition");
15727        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15728            .expect("transition");
15729        atn.add_transition(
15730            2,
15731            ParserTransitionSpec::Precedence {
15732                target: 3,
15733                precedence: 1,
15734            },
15735        )
15736        .expect("transition");
15737        atn.add_transition(
15738            3,
15739            ParserTransitionSpec::Predicate {
15740                target: 4,
15741                rule_index: 0,
15742                pred_index: 0,
15743                context_dependent: false,
15744            },
15745        )
15746        .expect("transition");
15747        atn.add_transition(
15748            4,
15749            ParserTransitionSpec::Atom {
15750                target: 1,
15751                label: 1,
15752            },
15753        )
15754        .expect("transition");
15755        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15756            .expect("transition");
15757        finish_atn(atn)
15758    }
15759
15760    fn left_recursive_loop_with_nullable_follow_call_atn(caller_symbol: i32) -> Atn {
15761        let mut atn = ParserAtnBuilder::new(2);
15762        for (state, kind, rule) in [
15763            (0, AtnStateKind::RuleStart, 0),
15764            (1, AtnStateKind::Basic, 0),
15765            (2, AtnStateKind::Basic, 0),
15766            (3, AtnStateKind::Basic, 0),
15767            (4, AtnStateKind::RuleStop, 0),
15768            (5, AtnStateKind::RuleStart, 1),
15769            (6, AtnStateKind::StarLoopEntry, 1),
15770            (7, AtnStateKind::Basic, 1),
15771            (8, AtnStateKind::Basic, 1),
15772            (9, AtnStateKind::LoopEnd, 1),
15773            (10, AtnStateKind::RuleStop, 1),
15774            (11, AtnStateKind::RuleStart, 2),
15775            (12, AtnStateKind::RuleStop, 2),
15776        ] {
15777            assert_eq!(
15778                atn.add_state(kind, Some(rule)).expect("state").index(),
15779                state
15780            );
15781            if state == 5 {
15782                atn.set_left_recursive_rule(state)
15783                    .expect("left-recursive rule start");
15784            } else if state == 6 {
15785                atn.set_precedence_rule_decision(state)
15786                    .expect("precedence decision");
15787            }
15788        }
15789        atn.set_rule_to_start_state(vec![0, 5, 11])
15790            .expect("rule start states");
15791        atn.set_rule_to_stop_state(vec![4, 10, 12])
15792            .expect("rule stop states");
15793        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15794            .expect("transition");
15795        atn.add_transition(
15796            1,
15797            ParserTransitionSpec::Rule {
15798                target: 5,
15799                rule_index: 1,
15800                follow_state: 2,
15801                precedence: 0,
15802            },
15803        )
15804        .expect("transition");
15805        atn.add_transition(
15806            2,
15807            ParserTransitionSpec::Rule {
15808                target: 11,
15809                rule_index: 2,
15810                follow_state: 3,
15811                precedence: 0,
15812            },
15813        )
15814        .expect("transition");
15815        atn.add_transition(
15816            3,
15817            ParserTransitionSpec::Atom {
15818                target: 4,
15819                label: caller_symbol,
15820            },
15821        )
15822        .expect("transition");
15823        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15824            .expect("transition");
15825        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 9 })
15826            .expect("transition");
15827        atn.add_transition(
15828            7,
15829            ParserTransitionSpec::Precedence {
15830                target: 8,
15831                precedence: 1,
15832            },
15833        )
15834        .expect("transition");
15835        atn.add_transition(
15836            8,
15837            ParserTransitionSpec::Atom {
15838                target: 6,
15839                label: 1,
15840            },
15841        )
15842        .expect("transition");
15843        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15844            .expect("transition");
15845        atn.add_transition(11, ParserTransitionSpec::Epsilon { target: 12 })
15846            .expect("transition");
15847        finish_atn(atn)
15848    }
15849
15850    fn left_recursive_loop_with_nullable_parent_return_atn(caller_symbol: i32) -> Atn {
15851        let mut atn = ParserAtnBuilder::new(2);
15852        for (state, kind, rule) in [
15853            (0, AtnStateKind::RuleStart, 0),
15854            (1, AtnStateKind::Basic, 0),
15855            (2, AtnStateKind::Basic, 0),
15856            (3, AtnStateKind::RuleStop, 0),
15857            (4, AtnStateKind::RuleStart, 1),
15858            (5, AtnStateKind::Basic, 1),
15859            (6, AtnStateKind::Basic, 1),
15860            (7, AtnStateKind::RuleStop, 1),
15861            (8, AtnStateKind::RuleStart, 2),
15862            (9, AtnStateKind::StarLoopEntry, 2),
15863            (10, AtnStateKind::Basic, 2),
15864            (11, AtnStateKind::Basic, 2),
15865            (12, AtnStateKind::LoopEnd, 2),
15866            (13, AtnStateKind::RuleStop, 2),
15867        ] {
15868            assert_eq!(
15869                atn.add_state(kind, Some(rule)).expect("state").index(),
15870                state
15871            );
15872            if state == 8 {
15873                atn.set_left_recursive_rule(state)
15874                    .expect("left-recursive rule start");
15875            } else if state == 9 {
15876                atn.set_precedence_rule_decision(state)
15877                    .expect("precedence decision");
15878            }
15879        }
15880        atn.set_rule_to_start_state(vec![0, 4, 8])
15881            .expect("rule start states");
15882        atn.set_rule_to_stop_state(vec![3, 7, 13])
15883            .expect("rule stop states");
15884        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15885            .expect("transition");
15886        atn.add_transition(
15887            1,
15888            ParserTransitionSpec::Rule {
15889                target: 4,
15890                rule_index: 1,
15891                follow_state: 2,
15892                precedence: 0,
15893            },
15894        )
15895        .expect("transition");
15896        atn.add_transition(
15897            2,
15898            ParserTransitionSpec::Atom {
15899                target: 3,
15900                label: caller_symbol,
15901            },
15902        )
15903        .expect("transition");
15904        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15905            .expect("transition");
15906        atn.add_transition(
15907            5,
15908            ParserTransitionSpec::Rule {
15909                target: 8,
15910                rule_index: 2,
15911                follow_state: 6,
15912                precedence: 0,
15913            },
15914        )
15915        .expect("transition");
15916        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15917            .expect("transition");
15918        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15919            .expect("transition");
15920        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 12 })
15921            .expect("transition");
15922        atn.add_transition(
15923            10,
15924            ParserTransitionSpec::Precedence {
15925                target: 11,
15926                precedence: 1,
15927            },
15928        )
15929        .expect("transition");
15930        atn.add_transition(
15931            11,
15932            ParserTransitionSpec::Atom {
15933                target: 9,
15934                label: 1,
15935            },
15936        )
15937        .expect("transition");
15938        atn.add_transition(12, ParserTransitionSpec::Epsilon { target: 13 })
15939            .expect("transition");
15940        finish_atn(atn)
15941    }
15942
15943    fn left_recursive_loop_with_recursive_operand_return_atn(caller_symbol: i32) -> Atn {
15944        let mut atn = ParserAtnBuilder::new(2);
15945        for (state, kind, rule) in [
15946            (0, AtnStateKind::RuleStart, 0),
15947            (1, AtnStateKind::Basic, 0),
15948            (2, AtnStateKind::Basic, 0),
15949            (3, AtnStateKind::RuleStop, 0),
15950            (4, AtnStateKind::RuleStart, 1),
15951            (5, AtnStateKind::StarLoopEntry, 1),
15952            (6, AtnStateKind::Basic, 1),
15953            (7, AtnStateKind::Basic, 1),
15954            (8, AtnStateKind::Basic, 1),
15955            (9, AtnStateKind::Basic, 1),
15956            (10, AtnStateKind::LoopEnd, 1),
15957            (11, AtnStateKind::RuleStop, 1),
15958        ] {
15959            assert_eq!(
15960                atn.add_state(kind, Some(rule)).expect("state").index(),
15961                state
15962            );
15963            if state == 4 {
15964                atn.set_left_recursive_rule(state)
15965                    .expect("left-recursive rule start");
15966            } else if state == 5 {
15967                atn.set_precedence_rule_decision(state)
15968                    .expect("precedence decision");
15969            }
15970        }
15971        atn.set_rule_to_start_state(vec![0, 4])
15972            .expect("rule start states");
15973        atn.set_rule_to_stop_state(vec![3, 11])
15974            .expect("rule stop states");
15975        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15976            .expect("transition");
15977        atn.add_transition(
15978            1,
15979            ParserTransitionSpec::Rule {
15980                target: 4,
15981                rule_index: 1,
15982                follow_state: 2,
15983                precedence: 0,
15984            },
15985        )
15986        .expect("transition");
15987        atn.add_transition(
15988            2,
15989            ParserTransitionSpec::Atom {
15990                target: 3,
15991                label: caller_symbol,
15992            },
15993        )
15994        .expect("transition");
15995        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15996            .expect("transition");
15997        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 10 })
15998            .expect("transition");
15999        atn.add_transition(
16000            6,
16001            ParserTransitionSpec::Precedence {
16002                target: 7,
16003                precedence: 1,
16004            },
16005        )
16006        .expect("transition");
16007        atn.add_transition(
16008            7,
16009            ParserTransitionSpec::Atom {
16010                target: 8,
16011                label: 1,
16012            },
16013        )
16014        .expect("transition");
16015        atn.add_transition(
16016            8,
16017            ParserTransitionSpec::Rule {
16018                target: 4,
16019                rule_index: 1,
16020                follow_state: 9,
16021                precedence: 2,
16022            },
16023        )
16024        .expect("transition");
16025        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 5 })
16026            .expect("transition");
16027        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
16028            .expect("transition");
16029        finish_atn(atn)
16030    }
16031
16032    #[test]
16033    fn left_recursive_loop_defers_overlapping_caller_lookahead() {
16034        let overlapping_atn = left_recursive_loop_with_caller_follow_atn(1);
16035        let unambiguous_atn = left_recursive_loop_with_caller_follow_atn(2);
16036
16037        let mut overlapping = parser_inside_left_recursive_callee(1);
16038        assert_eq!(
16039            overlapping.left_recursive_loop_enter_prediction(&overlapping_atn, 4, 0),
16040            None
16041        );
16042
16043        let mut unambiguous_enter = parser_inside_left_recursive_callee(1);
16044        assert_eq!(
16045            unambiguous_enter.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16046            Some(true)
16047        );
16048
16049        let mut unambiguous_exit = parser_inside_left_recursive_callee(2);
16050        assert_eq!(
16051            unambiguous_exit.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16052            Some(false)
16053        );
16054
16055        assert_eq!(
16056            overlapping.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16057            Some(true),
16058            "overlap results must not leak across ATNs"
16059        );
16060    }
16061
16062    #[test]
16063    fn left_recursive_loop_enters_after_nullable_operator_prefix() {
16064        let atn = left_recursive_loop_with_nullable_operator_prefix_atn();
16065        let mut parser = mini_parser(vec![
16066            TestToken::new(1).with_text("operator"),
16067            TestToken::eof("parser-test", 1, 1, 1),
16068        ]);
16069        parser.rule_context_stack = vec![RuleContextFrame {
16070            rule_index: 0,
16071            invoking_state: -1,
16072        }];
16073
16074        assert_eq!(
16075            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16076            Some(true)
16077        );
16078        assert_eq!(
16079            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16080            Some(true),
16081            "cached operator lookahead must preserve the nullable prefix return path"
16082        );
16083        assert_eq!(
16084            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16085            Some(true),
16086            "the nullable child must use its rule-call precedence, not the caller precedence"
16087        );
16088    }
16089
16090    #[test]
16091    fn left_recursive_loop_defers_multi_token_prefix_that_shadows_lower_single_token() {
16092        // Models Java `>` (relational, prec 1, one token) vs `>>` (shift, prec 2,
16093        // two tokens). At prec 2 only shift is viable; one-token lookahead on `>`
16094        // must defer so StarLoopEntry adaptive predict can exit when the second
16095        // `>` is absent (as in `a < b > c`).
16096        let atn = left_recursive_loop_with_shared_gt_prefix_atn();
16097        let mut parser = mini_parser(vec![
16098            TestToken::new(1).with_text(">"),
16099            TestToken::new(2).with_text("id"),
16100            TestToken::eof("parser-test", 1, 1, 1),
16101        ]);
16102        parser.rule_context_stack = vec![RuleContextFrame {
16103            rule_index: 0,
16104            invoking_state: -1,
16105        }];
16106
16107        assert_eq!(
16108            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16109            Some(true),
16110            "at low precedence relational `>` is a single-token operator"
16111        );
16112        assert_eq!(
16113            parser.left_recursive_loop_enter_prediction(&atn, 1, 1),
16114            Some(true),
16115            "relational remains single-token at its own precedence"
16116        );
16117        assert_eq!(
16118            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16119            None,
16120            "at shift precedence, bare `>` must not force enter"
16121        );
16122    }
16123
16124    #[test]
16125    fn left_recursive_loop_preserves_rule_wrapped_operator_continuation() {
16126        let atn = left_recursive_loop_with_rule_wrapped_gt_prefix_atn();
16127        let mut parser = mini_parser(vec![
16128            TestToken::new(1).with_text(">"),
16129            TestToken::new(2).with_text("id"),
16130            TestToken::eof("parser-test", 1, 1, 1),
16131        ]);
16132        parser.rule_context_stack = vec![RuleContextFrame {
16133            rule_index: 0,
16134            invoking_state: -1,
16135        }];
16136
16137        assert_eq!(
16138            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16139            Some(true),
16140            "the direct relational alternative remains a one-token operator"
16141        );
16142        assert_eq!(
16143            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16144            None,
16145            "a token matched in the helper rule must return to the second shift token"
16146        );
16147    }
16148
16149    #[test]
16150    fn left_recursive_loop_preserves_predicate_and_multi_token_reachability() {
16151        let atn = left_recursive_loop_with_predicate_and_multi_token_prefix_atn();
16152        let mut parser = mini_parser(vec![
16153            TestToken::new(1).with_text(">"),
16154            TestToken::new(2).with_text("id"),
16155            TestToken::eof("parser-test", 1, 1, 1),
16156        ]);
16157        parser.rule_context_stack = vec![RuleContextFrame {
16158            rule_index: 0,
16159            invoking_state: -1,
16160        }];
16161
16162        assert_eq!(
16163            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16164            None,
16165            "a predicate-gated single-token path must not be hidden by a multi-token path"
16166        );
16167    }
16168
16169    #[test]
16170    fn left_recursive_loop_defers_predicate_guarded_operator() {
16171        let atn = left_recursive_loop_with_predicate_guarded_operator_atn();
16172        let mut parser = mini_parser_with_hooks(
16173            vec![
16174                TestToken::new(1).with_text("operator"),
16175                TestToken::eof("parser-test", 1, 1, 1),
16176            ],
16177            RejectingPredicateHooks::default(),
16178        );
16179        parser.rule_context_stack = vec![RuleContextFrame {
16180            rule_index: 0,
16181            invoking_state: -1,
16182        }];
16183
16184        assert_eq!(
16185            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16186            None,
16187            "a false predicate must be evaluated before entering the operator alternative"
16188        );
16189        assert_eq!(
16190            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16191            None,
16192            "cached predicate-dependent lookahead must keep deferring"
16193        );
16194    }
16195
16196    #[test]
16197    fn left_recursive_loop_defers_through_nullable_caller_rule_call() {
16198        let atn = left_recursive_loop_with_nullable_follow_call_atn(1);
16199        let mut parser = parser_inside_left_recursive_callee(1);
16200
16201        assert_eq!(
16202            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16203            None
16204        );
16205        assert_eq!(
16206            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16207            None,
16208            "the cached overlap must preserve the nullable child return path"
16209        );
16210    }
16211
16212    #[test]
16213    fn left_recursive_loop_defers_through_nullable_parent_return() {
16214        let atn = left_recursive_loop_with_nullable_parent_return_atn(1);
16215        let mut parser = mini_parser(vec![
16216            TestToken::new(1).with_text("lookahead"),
16217            TestToken::eof("parser-test", 1, 1, 1),
16218        ]);
16219        parser.rule_context_stack = vec![
16220            RuleContextFrame {
16221                rule_index: 0,
16222                invoking_state: -1,
16223            },
16224            RuleContextFrame {
16225                rule_index: 1,
16226                invoking_state: 1,
16227            },
16228            RuleContextFrame {
16229                rule_index: 2,
16230                invoking_state: 5,
16231            },
16232        ];
16233
16234        assert_eq!(
16235            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16236            None,
16237            "a nullable caller must unwind to its parent's consuming follow path"
16238        );
16239        assert_eq!(
16240            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16241            None,
16242            "the caller-overlap cache must not retain a false negative"
16243        );
16244    }
16245
16246    #[test]
16247    fn left_recursive_loop_defers_after_recursive_operand_returns_to_loop() {
16248        let atn = left_recursive_loop_with_recursive_operand_return_atn(1);
16249        let mut parser = mini_parser(vec![
16250            TestToken::new(1).with_text("lookahead"),
16251            TestToken::eof("parser-test", 1, 1, 1),
16252        ]);
16253        parser.rule_context_stack = vec![
16254            RuleContextFrame {
16255                rule_index: 0,
16256                invoking_state: -1,
16257            },
16258            RuleContextFrame {
16259                rule_index: 1,
16260                invoking_state: 1,
16261            },
16262            RuleContextFrame {
16263                rule_index: 1,
16264                invoking_state: 8,
16265            },
16266        ];
16267
16268        assert_eq!(
16269            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16270            None,
16271            "a recursive operand return must preserve its parent caller context"
16272        );
16273        assert_eq!(
16274            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16275            None,
16276            "the caller-overlap cache must preserve the loop-boundary return"
16277        );
16278    }
16279
16280    fn token_then_eof_atn() -> Atn {
16281        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16282            4, 1, 2, // version, parser, max token type
16283            3, // states
16284            2, 0, // rule start
16285            1, 0, // basic
16286            7, 0, // rule stop
16287            0, // non-greedy states
16288            0, // precedence states
16289            1, // rules
16290            0, // rule 0 start
16291            0, // modes
16292            0, // sets
16293            2, // transitions
16294            0, 1, 5, 1, 0, 0, // match token 1
16295            1, 2, 5, -1, 0, 0, // match EOF
16296            0, // decisions
16297        ]))
16298        .deserialize_parser()
16299        .expect("artificial parser ATN should deserialize")
16300    }
16301
16302    fn epsilon_cycle_atn() -> Atn {
16303        let mut atn = ParserAtnBuilder::new(1);
16304        for (state_number, kind) in [
16305            (0, AtnStateKind::RuleStart),
16306            (1, AtnStateKind::Basic),
16307            (2, AtnStateKind::RuleStop),
16308        ] {
16309            assert_eq!(
16310                atn.add_state(kind, Some(0)).expect("state").index(),
16311                state_number
16312            );
16313        }
16314        atn.set_rule_to_start_state(vec![0])
16315            .expect("rule start states");
16316        atn.set_rule_to_stop_state(vec![2])
16317            .expect("rule stop states");
16318        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16319            .expect("transition");
16320        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16321            .expect("self-cycle transition");
16322        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16323            .expect("exit transition");
16324        finish_atn(atn)
16325    }
16326
16327    fn committed_non_consuming_cycle_atn() -> Atn {
16328        let mut atn = ParserAtnBuilder::new(1);
16329        for (state_number, kind) in [
16330            (0, AtnStateKind::RuleStart),
16331            (1, AtnStateKind::Basic),
16332            (2, AtnStateKind::RuleStop),
16333        ] {
16334            assert_eq!(
16335                atn.add_state(kind, Some(0)).expect("state").index(),
16336                state_number
16337            );
16338        }
16339        atn.set_rule_to_start_state(vec![0])
16340            .expect("rule start states");
16341        atn.set_rule_to_stop_state(vec![2])
16342            .expect("rule stop states");
16343        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16344            .expect("cycle entry");
16345        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16346            .expect("self-cycle transition");
16347        finish_atn(atn)
16348    }
16349
16350    fn eof_then_action_atn() -> Atn {
16351        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16352            4, 1, 1, // version, parser, max token type
16353            3, // states
16354            2, 0, // rule start
16355            1, 0, // basic
16356            7, 0, // rule stop
16357            0, // non-greedy states
16358            0, // precedence states
16359            1, // rules
16360            0, // rule 0 start
16361            0, // modes
16362            0, // sets
16363            2, // transitions
16364            0, 1, 5, -1, 0, 0, // match EOF
16365            1, 2, 6, 0, 0, 0, // parser action
16366            0, // decisions
16367        ]))
16368        .deserialize_parser()
16369        .expect("artificial parser ATN should deserialize")
16370    }
16371
16372    fn noop_action_then_token_then_eof_atn() -> Atn {
16373        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16374            4, 1, 2, // version, parser, max token type
16375            4, // states
16376            2, 0, // rule start
16377            1, 0, // basic
16378            1, 0, // basic
16379            7, 0, // rule stop
16380            0, // non-greedy states
16381            0, // precedence states
16382            1, // rules
16383            0, // rule 0 start
16384            0, // modes
16385            0, // sets
16386            3, // transitions
16387            0, 1, 6, 0, -1, 0, // no-op parser action
16388            1, 2, 5, 1, 0, 0, // match token 1
16389            2, 3, 5, -1, 0, 0, // match EOF
16390            0, // decisions
16391        ]))
16392        .deserialize_parser()
16393        .expect("artificial no-op action ATN should deserialize")
16394    }
16395
16396    fn committed_action_then_predicate_atn() -> Atn {
16397        let mut atn = ParserAtnBuilder::new(1);
16398        for (state_number, kind) in [
16399            (0, AtnStateKind::RuleStart),
16400            (1, AtnStateKind::Basic),
16401            (2, AtnStateKind::Basic),
16402            (3, AtnStateKind::Basic),
16403            (4, AtnStateKind::RuleStop),
16404        ] {
16405            assert_eq!(
16406                atn.add_state(kind, Some(0)).expect("state").index(),
16407                state_number
16408            );
16409        }
16410        atn.set_rule_to_start_state(vec![0])
16411            .expect("rule start states");
16412        atn.set_rule_to_stop_state(vec![4])
16413            .expect("rule stop states");
16414        atn.add_transition(
16415            0,
16416            ParserTransitionSpec::Action {
16417                target: 1,
16418                rule_index: 0,
16419                action_index: None,
16420                context_dependent: false,
16421            },
16422        )
16423        .expect("action transition");
16424        atn.add_transition(
16425            1,
16426            ParserTransitionSpec::Predicate {
16427                target: 2,
16428                rule_index: 0,
16429                pred_index: 0,
16430                context_dependent: false,
16431            },
16432        )
16433        .expect("predicate transition");
16434        atn.add_transition(
16435            2,
16436            ParserTransitionSpec::Atom {
16437                target: 3,
16438                label: 1,
16439            },
16440        )
16441        .expect("token transition");
16442        atn.add_transition(
16443            3,
16444            ParserTransitionSpec::Atom {
16445                target: 4,
16446                label: TOKEN_EOF,
16447            },
16448        )
16449        .expect("EOF transition");
16450        finish_atn(atn)
16451    }
16452
16453    /// ATN for `parent : child[42] {Parent();}; child[int value] : {Child();} EOF;`.
16454    fn parameterized_child_action_eof_atn() -> Atn {
16455        let mut atn = ParserAtnBuilder::new(1);
16456        for (state_number, kind, rule_index) in [
16457            (0, AtnStateKind::RuleStart, 0),
16458            (1, AtnStateKind::Basic, 0),
16459            (2, AtnStateKind::Basic, 0),
16460            (3, AtnStateKind::RuleStop, 0),
16461            (4, AtnStateKind::RuleStart, 1),
16462            (5, AtnStateKind::Basic, 1),
16463            (6, AtnStateKind::RuleStop, 1),
16464        ] {
16465            assert_eq!(
16466                atn.add_state(kind, Some(rule_index))
16467                    .expect("state")
16468                    .index(),
16469                state_number
16470            );
16471        }
16472        atn.set_rule_to_start_state(vec![0, 4])
16473            .expect("rule start states");
16474        atn.set_rule_to_stop_state(vec![3, 6])
16475            .expect("rule stop states");
16476        atn.add_transition(
16477            0,
16478            ParserTransitionSpec::Rule {
16479                target: 4,
16480                rule_index: 1,
16481                follow_state: 1,
16482                precedence: 0,
16483            },
16484        )
16485        .expect("parameterized child call");
16486        atn.add_transition(
16487            1,
16488            ParserTransitionSpec::Action {
16489                target: 2,
16490                rule_index: 0,
16491                action_index: None,
16492                context_dependent: false,
16493            },
16494        )
16495        .expect("parent action");
16496        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16497            .expect("parent stop");
16498        atn.add_transition(
16499            4,
16500            ParserTransitionSpec::Action {
16501                target: 5,
16502                rule_index: 1,
16503                action_index: None,
16504                context_dependent: false,
16505            },
16506        )
16507        .expect("child action");
16508        atn.add_transition(
16509            5,
16510            ParserTransitionSpec::Atom {
16511                target: 6,
16512                label: TOKEN_EOF,
16513            },
16514        )
16515        .expect("child EOF");
16516        finish_atn(atn)
16517    }
16518
16519    fn action_then_nested_rule_atn() -> Atn {
16520        let mut atn = ParserAtnBuilder::new(1);
16521        for (state_number, kind, rule_index) in [
16522            (0, AtnStateKind::RuleStart, 0),
16523            (1, AtnStateKind::Basic, 0),
16524            (2, AtnStateKind::Basic, 0),
16525            (3, AtnStateKind::RuleStop, 0),
16526            (4, AtnStateKind::RuleStart, 1),
16527            (5, AtnStateKind::RuleStop, 1),
16528        ] {
16529            assert_eq!(
16530                atn.add_state(kind, Some(rule_index))
16531                    .expect("state")
16532                    .index(),
16533                state_number
16534            );
16535        }
16536        atn.set_rule_to_start_state(vec![0, 4])
16537            .expect("rule start states");
16538        atn.set_rule_to_stop_state(vec![3, 5])
16539            .expect("rule stop states");
16540        atn.add_transition(
16541            0,
16542            ParserTransitionSpec::Action {
16543                target: 1,
16544                rule_index: 0,
16545                action_index: None,
16546                context_dependent: false,
16547            },
16548        )
16549        .expect("parent action");
16550        atn.add_transition(
16551            1,
16552            ParserTransitionSpec::Rule {
16553                target: 4,
16554                rule_index: 1,
16555                follow_state: 2,
16556                precedence: 0,
16557            },
16558        )
16559        .expect("nested rule call");
16560        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16561            .expect("parent stop");
16562        atn.add_transition(
16563            4,
16564            ParserTransitionSpec::Atom {
16565                target: 5,
16566                label: TOKEN_EOF,
16567            },
16568        )
16569        .expect("child EOF");
16570        finish_atn(atn)
16571    }
16572
16573    fn losing_alternative_action_atn() -> Atn {
16574        let mut atn = ParserAtnBuilder::new(2);
16575        for (state_number, kind) in [
16576            (0, AtnStateKind::RuleStart),
16577            (1, AtnStateKind::BlockStart),
16578            (2, AtnStateKind::Basic),
16579            (3, AtnStateKind::Basic),
16580            (4, AtnStateKind::BlockEnd),
16581            (5, AtnStateKind::RuleStop),
16582        ] {
16583            assert_eq!(
16584                atn.add_state(kind, Some(0)).expect("state").index(),
16585                state_number
16586            );
16587        }
16588        atn.set_rule_to_start_state(vec![0])
16589            .expect("rule start states");
16590        atn.set_rule_to_stop_state(vec![5])
16591            .expect("rule stop states");
16592        atn.set_end_state(1, 4).expect("block end state");
16593        atn.add_decision_state(1).expect("decision state");
16594        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16595            .expect("entry transition");
16596        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16597            .expect("first alternative");
16598        atn.add_transition(
16599            1,
16600            ParserTransitionSpec::Atom {
16601                target: 4,
16602                label: 2,
16603            },
16604        )
16605        .expect("second alternative");
16606        atn.add_transition(
16607            2,
16608            ParserTransitionSpec::Action {
16609                target: 3,
16610                rule_index: 0,
16611                action_index: None,
16612                context_dependent: false,
16613            },
16614        )
16615        .expect("losing action");
16616        atn.add_transition(
16617            3,
16618            ParserTransitionSpec::Atom {
16619                target: 4,
16620                label: 1,
16621            },
16622        )
16623        .expect("first alternative token");
16624        atn.add_transition(
16625            4,
16626            ParserTransitionSpec::Atom {
16627                target: 5,
16628                label: TOKEN_EOF,
16629            },
16630        )
16631        .expect("EOF transition");
16632        finish_atn(atn)
16633    }
16634
16635    fn committed_action_star_loop_atn() -> Atn {
16636        let mut atn = ParserAtnBuilder::new(1);
16637        for (state_number, kind) in [
16638            (0, AtnStateKind::RuleStart),
16639            (1, AtnStateKind::StarLoopEntry),
16640            (2, AtnStateKind::Basic),
16641            (3, AtnStateKind::Basic),
16642            (4, AtnStateKind::StarLoopBack),
16643            (5, AtnStateKind::LoopEnd),
16644            (6, AtnStateKind::RuleStop),
16645        ] {
16646            assert_eq!(
16647                atn.add_state(kind, Some(0)).expect("state").index(),
16648                state_number
16649            );
16650        }
16651        atn.set_rule_to_start_state(vec![0])
16652            .expect("rule start states");
16653        atn.set_rule_to_stop_state(vec![6])
16654            .expect("rule stop states");
16655        atn.add_decision_state(1).expect("decision state");
16656        atn.set_loop_back_state(5, 4).expect("loop back state");
16657        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16658            .expect("entry transition");
16659        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16660            .expect("loop body");
16661        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
16662            .expect("loop exit");
16663        atn.add_transition(
16664            2,
16665            ParserTransitionSpec::Action {
16666                target: 3,
16667                rule_index: 0,
16668                action_index: None,
16669                context_dependent: false,
16670            },
16671        )
16672        .expect("loop action");
16673        atn.add_transition(
16674            3,
16675            ParserTransitionSpec::Atom {
16676                target: 4,
16677                label: 1,
16678            },
16679        )
16680        .expect("loop token");
16681        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
16682            .expect("loop back");
16683        atn.add_transition(
16684            5,
16685            ParserTransitionSpec::Atom {
16686                target: 6,
16687                label: TOKEN_EOF,
16688            },
16689        )
16690        .expect("EOF transition");
16691        finish_atn(atn)
16692    }
16693
16694    fn committed_action_left_recursive_atn() -> Atn {
16695        let mut atn = ParserAtnBuilder::new(4);
16696        for (state, kind) in [
16697            (0, AtnStateKind::RuleStart),
16698            (1, AtnStateKind::BlockStart),
16699            (2, AtnStateKind::StarLoopEntry),
16700            (3, AtnStateKind::StarBlockStart),
16701            (4, AtnStateKind::Basic),
16702            (5, AtnStateKind::Basic),
16703            (6, AtnStateKind::Basic),
16704            (7, AtnStateKind::StarLoopBack),
16705            (8, AtnStateKind::LoopEnd),
16706            (9, AtnStateKind::RuleStop),
16707            (10, AtnStateKind::Basic),
16708        ] {
16709            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
16710        }
16711        atn.set_left_recursive_rule(0)
16712            .expect("left-recursive rule start");
16713        atn.set_precedence_rule_decision(2)
16714            .expect("precedence decision");
16715        atn.set_loop_back_state(8, 7).expect("loop-back state");
16716        atn.set_rule_to_start_state(vec![0])
16717            .expect("rule start states");
16718        atn.set_rule_to_stop_state(vec![9])
16719            .expect("rule stop states");
16720        for state in [1, 2, 3] {
16721            atn.add_decision_state(state).expect("decision state");
16722        }
16723        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
16724            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
16725                .expect("epsilon transition");
16726        }
16727        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3)] {
16728            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
16729                .expect("token transition");
16730        }
16731        for (target, precedence) in [(4, 2), (5, 1)] {
16732            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
16733                .expect("operator precedence");
16734        }
16735        atn.add_transition(
16736            6,
16737            ParserTransitionSpec::Action {
16738                target: 10,
16739                rule_index: 0,
16740                action_index: None,
16741                context_dependent: false,
16742            },
16743        )
16744        .expect("operator action");
16745        atn.add_transition(
16746            10,
16747            ParserTransitionSpec::Atom {
16748                target: 7,
16749                label: 1,
16750            },
16751        )
16752        .expect("right operand");
16753        finish_atn(atn)
16754    }
16755
16756    fn two_alt_decision_atn() -> Atn {
16757        let mut atn = ParserAtnBuilder::new(2);
16758        assert_eq!(
16759            atn.add_state(AtnStateKind::RuleStart, Some(0))
16760                .expect("state")
16761                .index(),
16762            0
16763        );
16764        assert_eq!(
16765            atn.add_state(AtnStateKind::BlockStart, Some(0))
16766                .expect("state")
16767                .index(),
16768            1
16769        );
16770        assert_eq!(
16771            atn.add_state(AtnStateKind::Basic, Some(0))
16772                .expect("state")
16773                .index(),
16774            2
16775        );
16776        assert_eq!(
16777            atn.add_state(AtnStateKind::Basic, Some(0))
16778                .expect("state")
16779                .index(),
16780            3
16781        );
16782        assert_eq!(
16783            atn.add_state(AtnStateKind::BlockEnd, Some(0))
16784                .expect("state")
16785                .index(),
16786            4
16787        );
16788        assert_eq!(
16789            atn.add_state(AtnStateKind::RuleStop, Some(0))
16790                .expect("state")
16791                .index(),
16792            5
16793        );
16794        atn.set_rule_to_start_state(vec![0])
16795            .expect("rule start states");
16796        atn.set_rule_to_stop_state(vec![5])
16797            .expect("rule stop states");
16798        atn.add_decision_state(1).expect("decision state");
16799        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16800            .expect("transition");
16801        atn.add_transition(
16802            1,
16803            ParserTransitionSpec::Atom {
16804                target: 2,
16805                label: 1,
16806            },
16807        )
16808        .expect("transition");
16809        atn.add_transition(
16810            1,
16811            ParserTransitionSpec::Atom {
16812                target: 3,
16813                label: 2,
16814            },
16815        )
16816        .expect("transition");
16817        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 4 })
16818            .expect("transition");
16819        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
16820            .expect("transition");
16821        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
16822            .expect("transition");
16823        finish_atn(atn)
16824    }
16825
16826    /// ATN for `start : (A)? B EOF ;` (A=1, B=2, C=3, max token type 3).
16827    /// State 1 is the nullable optional-block decision; its sync set is {A, B}.
16828    fn optional_then_b_eof_atn() -> Atn {
16829        let mut atn = ParserAtnBuilder::new(3);
16830        assert_eq!(
16831            atn.add_state(AtnStateKind::RuleStart, Some(0))
16832                .expect("state")
16833                .index(),
16834            0
16835        );
16836        assert_eq!(
16837            atn.add_state(AtnStateKind::BlockStart, Some(0))
16838                .expect("state")
16839                .index(),
16840            1
16841        );
16842        assert_eq!(
16843            atn.add_state(AtnStateKind::Basic, Some(0))
16844                .expect("state")
16845                .index(),
16846            2
16847        );
16848        assert_eq!(
16849            atn.add_state(AtnStateKind::Basic, Some(0))
16850                .expect("state")
16851                .index(),
16852            3
16853        );
16854        assert_eq!(
16855            atn.add_state(AtnStateKind::Basic, Some(0))
16856                .expect("state")
16857                .index(),
16858            4
16859        );
16860        assert_eq!(
16861            atn.add_state(AtnStateKind::RuleStop, Some(0))
16862                .expect("state")
16863                .index(),
16864            5
16865        );
16866        atn.set_rule_to_start_state(vec![0])
16867            .expect("rule start states");
16868        atn.set_rule_to_stop_state(vec![5])
16869            .expect("rule stop states");
16870        atn.add_decision_state(1).expect("decision state");
16871        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16872            .expect("transition");
16873        // Optional block: match A then fall through, or skip straight to state 3.
16874        atn.add_transition(
16875            1,
16876            ParserTransitionSpec::Atom {
16877                target: 3,
16878                label: 1,
16879            },
16880        )
16881        .expect("transition");
16882        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
16883            .expect("transition");
16884        // Match B, then EOF.
16885        atn.add_transition(
16886            3,
16887            ParserTransitionSpec::Atom {
16888                target: 4,
16889                label: 2,
16890            },
16891        )
16892        .expect("transition");
16893        atn.add_transition(
16894            4,
16895            ParserTransitionSpec::Atom {
16896                target: 5,
16897                label: TOKEN_EOF,
16898            },
16899        )
16900        .expect("transition");
16901        finish_atn(atn)
16902    }
16903
16904    #[test]
16905    fn sync_decision_deletes_only_a_single_token() {
16906        // ANTLR sync recovery deletes exactly one token, only when LA(2) is
16907        // expected. `(A)? B EOF` at the optional-block decision:
16908        //  - `C B`   -> single-token deletion: one error node for the extra `C`.
16909        //  - `C C B` -> LA(2) is `C` (not expected), so NO deletion; sync returns
16910        //               without consuming and records the expected set for the
16911        //               subsequent mismatch (the parser must not over-consume both
16912        //               `C`s and accept the input).
16913        let atn = optional_then_b_eof_atn();
16914
16915        let mut single = mini_parser(vec![
16916            TestToken::new(3).with_text("c"),
16917            TestToken::new(2).with_text("b"),
16918            TestToken::eof("parser-test", 1, 2, 2),
16919        ]);
16920        single.rule_context_stack = vec![RuleContextFrame {
16921            rule_index: 0,
16922            invoking_state: 0,
16923        }];
16924        let children = single
16925            .sync_decision(&atn, 1, true, false)
16926            .expect("single extraneous token recovers");
16927        assert_eq!(children.len(), 1);
16928        assert_eq!(single.node(children[0]).kind(), NodeKind::Error);
16929        assert_eq!(single.number_of_syntax_errors(), 1);
16930        // Exactly one token consumed (the cursor now sits on `b`).
16931        assert_eq!(single.la(1), 2);
16932
16933        let mut double = mini_parser(vec![
16934            TestToken::new(3).with_text("c"),
16935            TestToken::new(3).with_text("c"),
16936            TestToken::new(2).with_text("b"),
16937            TestToken::eof("parser-test", 1, 3, 3),
16938        ]);
16939        double.rule_context_stack = vec![RuleContextFrame {
16940            rule_index: 0,
16941            invoking_state: 0,
16942        }];
16943        let result = double.sync_decision(&atn, 1, true, false);
16944        // No single-token deletion fires (LA(2) is `c`, not expected): sync must NOT
16945        // consume either `c`. It reports the mismatch at the first `c` (so the parser
16946        // does not over-consume both and accept the input). Nothing is consumed, so
16947        // the cursor still sits on the first `c` for rule-level recovery.
16948        let error = result.expect_err("two extraneous tokens must not be deleted by sync");
16949        match error {
16950            AntlrError::ParserError { message, .. } => {
16951                assert!(message.starts_with("mismatched input"), "got: {message}");
16952            }
16953            other => panic!("expected a mismatched-input ParserError, got {other:?}"),
16954        }
16955        assert_eq!(double.la(1), 3);
16956    }
16957
16958    /// The real serialized ATN that `antlr4-rust-gen` emits for
16959    /// `grammar T; s : A* EOF; A:'a'; C:'c';` — a `*` loop whose follow set after
16960    /// the loop is `EOF`. The loop decision is state 5.
16961    fn star_loop_then_eof_atn() -> Atn {
16962        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16963            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,
16964            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,
16965            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,
16966            0, 0, 1, 9, 1, 1, 0, 0, 0, 1, 5,
16967        ]))
16968        .deserialize_parser()
16969        .expect("star-loop-then-EOF ATN should deserialize")
16970    }
16971
16972    /// ATN for `entry : nested EOF; nested : A*;`.
16973    ///
16974    /// State 5 is nullable within `nested`; its caller follow is EOF.
16975    fn nested_star_rule_atn() -> Atn {
16976        let mut atn = ParserAtnBuilder::new(2);
16977        for (state_number, kind, rule_index) in [
16978            (0, AtnStateKind::RuleStart, 0),
16979            (1, AtnStateKind::Basic, 0),
16980            (2, AtnStateKind::Basic, 0),
16981            (3, AtnStateKind::RuleStop, 0),
16982            (4, AtnStateKind::RuleStart, 1),
16983            (5, AtnStateKind::StarLoopEntry, 1),
16984            (6, AtnStateKind::Basic, 1),
16985            (7, AtnStateKind::StarLoopBack, 1),
16986            (8, AtnStateKind::LoopEnd, 1),
16987            (9, AtnStateKind::RuleStop, 1),
16988        ] {
16989            assert_eq!(
16990                atn.add_state(kind, Some(rule_index))
16991                    .expect("state")
16992                    .index(),
16993                state_number
16994            );
16995        }
16996        atn.set_rule_to_start_state(vec![0, 4])
16997            .expect("rule start states");
16998        atn.set_rule_to_stop_state(vec![3, 9])
16999            .expect("rule stop states");
17000        atn.add_decision_state(5).expect("decision state");
17001        atn.set_loop_back_state(8, 7).expect("loop back state");
17002        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17003            .expect("transition");
17004        atn.add_transition(
17005            1,
17006            ParserTransitionSpec::Rule {
17007                target: 4,
17008                rule_index: 1,
17009                follow_state: 2,
17010                precedence: 0,
17011            },
17012        )
17013        .expect("transition");
17014        atn.add_transition(
17015            2,
17016            ParserTransitionSpec::Atom {
17017                target: 3,
17018                label: TOKEN_EOF,
17019            },
17020        )
17021        .expect("transition");
17022        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
17023            .expect("transition");
17024        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
17025            .expect("transition");
17026        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 8 })
17027            .expect("transition");
17028        atn.add_transition(
17029            6,
17030            ParserTransitionSpec::Atom {
17031                target: 7,
17032                label: 1,
17033            },
17034        )
17035        .expect("transition");
17036        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 5 })
17037            .expect("transition");
17038        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17039            .expect("transition");
17040        finish_atn(atn)
17041    }
17042
17043    /// ATN for `s : a+ Y ; a : X ;`.
17044    ///
17045    /// At EOF, recovery can synthesize an empty failed `a` child. The enclosing
17046    /// `+` loop must not treat that zero-width child as a successful iteration
17047    /// and then re-enter the loop at the same token index.
17048    fn plus_loop_with_recovering_body_atn() -> Atn {
17049        let mut atn = ParserAtnBuilder::new(2);
17050        assert_eq!(
17051            atn.add_state(AtnStateKind::RuleStart, Some(0))
17052                .expect("state")
17053                .index(),
17054            0
17055        );
17056        assert_eq!(
17057            atn.add_state(AtnStateKind::PlusBlockStart, Some(0))
17058                .expect("state")
17059                .index(),
17060            1
17061        );
17062        assert_eq!(
17063            atn.add_state(AtnStateKind::Basic, Some(0))
17064                .expect("state")
17065                .index(),
17066            2
17067        );
17068        assert_eq!(
17069            atn.add_state(AtnStateKind::BlockEnd, Some(0))
17070                .expect("state")
17071                .index(),
17072            3
17073        );
17074        assert_eq!(
17075            atn.add_state(AtnStateKind::PlusLoopBack, Some(0))
17076                .expect("state")
17077                .index(),
17078            4
17079        );
17080        assert_eq!(
17081            atn.add_state(AtnStateKind::LoopEnd, Some(0))
17082                .expect("state")
17083                .index(),
17084            5
17085        );
17086        assert_eq!(
17087            atn.add_state(AtnStateKind::RuleStop, Some(0))
17088                .expect("state")
17089                .index(),
17090            6
17091        );
17092        assert_eq!(
17093            atn.add_state(AtnStateKind::RuleStart, Some(1))
17094                .expect("state")
17095                .index(),
17096            7
17097        );
17098        assert_eq!(
17099            atn.add_state(AtnStateKind::Basic, Some(1))
17100                .expect("state")
17101                .index(),
17102            8
17103        );
17104        assert_eq!(
17105            atn.add_state(AtnStateKind::RuleStop, Some(1))
17106                .expect("state")
17107                .index(),
17108            9
17109        );
17110        atn.set_rule_to_start_state(vec![0, 7])
17111            .expect("rule start states");
17112        atn.set_rule_to_stop_state(vec![6, 9])
17113            .expect("rule stop states");
17114        atn.set_end_state(1, 3).expect("block end state");
17115        atn.set_loop_back_state(5, 4).expect("loop back state");
17116        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17117            .expect("transition");
17118        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17119            .expect("transition");
17120        atn.add_transition(
17121            2,
17122            ParserTransitionSpec::Rule {
17123                target: 7,
17124                rule_index: 1,
17125                follow_state: 3,
17126                precedence: 0,
17127            },
17128        )
17129        .expect("transition");
17130        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
17131            .expect("transition");
17132        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
17133            .expect("transition");
17134        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
17135            .expect("transition");
17136        atn.add_transition(
17137            5,
17138            ParserTransitionSpec::Atom {
17139                target: 6,
17140                label: 2,
17141            },
17142        )
17143        .expect("transition");
17144        atn.add_transition(
17145            7,
17146            ParserTransitionSpec::Atom {
17147                target: 8,
17148                label: 1,
17149            },
17150        )
17151        .expect("transition");
17152        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17153            .expect("transition");
17154        finish_atn(atn)
17155    }
17156
17157    #[test]
17158    fn runtime_options_default_exits_recovering_empty_plus_iteration() {
17159        let atn = plus_loop_with_recovering_body_atn();
17160        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17161
17162        let error = parser
17163            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
17164            .expect_err("EOF recovery should report a bounded mismatch");
17165
17166        let AntlrError::ParserError { message, .. } = error else {
17167            panic!("expected ParserError, got {error:?}");
17168        };
17169        insta::assert_snapshot!(message, @"mismatched input '<EOF>' expecting {'x', 2}");
17170        assert_eq!(parser.number_of_syntax_errors(), 1);
17171        assert_eq!(parser.input.index(), 0, "EOF remains unconsumed");
17172    }
17173
17174    #[test]
17175    fn sync_decision_deletes_token_before_eof_at_loop_back() {
17176        // `s : A* EOF` on `c`: the loop decision (state 5) can recover onto EOF.
17177        // At the loop ENTRY (loop_back = false) a single unexpected token before
17178        // EOF is deleted as an error node (then the generated EOF match consumes
17179        // the real EOF) — matching ANTLR's `(s c <EOF>)` + "extraneous input".
17180        // EOF must be a valid scan-stop for this to fire.
17181        let atn = star_loop_then_eof_atn();
17182        let mut parser = mini_parser(vec![
17183            TestToken::new(2).with_text("c"),
17184            TestToken::eof("parser-test", 1, 1, 1),
17185        ]);
17186        parser.rule_context_stack = vec![RuleContextFrame {
17187            rule_index: 0,
17188            invoking_state: 0,
17189        }];
17190        let children = parser
17191            .sync_decision(&atn, 5, true, false)
17192            .expect("single token before EOF recovers");
17193        assert_eq!(children.len(), 1);
17194        assert_eq!(parser.node(children[0]).kind(), NodeKind::Error);
17195        assert_eq!(parser.number_of_syntax_errors(), 1);
17196        assert_eq!(
17197            parser.la(1),
17198            TOKEN_EOF,
17199            "EOF is left for the rule's EOF match"
17200        );
17201    }
17202
17203    #[test]
17204    fn sync_decision_does_not_delete_two_tokens_before_eof_at_loop_entry() {
17205        // `s : A* EOF` on `c c`: at the loop ENTRY (loop_back = false) ANTLR does
17206        // single-token deletion, which fails because LA(2) = `c` is not expected —
17207        // so it reports `mismatched input` and consumes nothing (ANTLR: `(s c c)`
17208        // with no EOF). The scan must NOT multi-token-consume both `c`s here.
17209        let atn = star_loop_then_eof_atn();
17210        let mut parser = mini_parser(vec![
17211            TestToken::new(2).with_text("c"),
17212            TestToken::new(2).with_text("c"),
17213            TestToken::eof("parser-test", 1, 2, 2),
17214        ]);
17215        parser.rule_context_stack = vec![RuleContextFrame {
17216            rule_index: 0,
17217            invoking_state: 0,
17218        }];
17219        let error = parser
17220            .sync_decision(&atn, 5, true, false)
17221            .expect_err("two tokens at the loop entry must not be deleted");
17222        match error {
17223            AntlrError::ParserError { message, .. } => {
17224                assert!(message.starts_with("mismatched input"), "got: {message}");
17225            }
17226            other => panic!("expected mismatched-input ParserError, got {other:?}"),
17227        }
17228        assert_eq!(
17229            parser.la(1),
17230            2,
17231            "nothing consumed; cursor still on first `c`"
17232        );
17233    }
17234
17235    #[test]
17236    fn sync_decision_consumes_until_eof_at_loop_back() {
17237        // Same `s : A* EOF` decision, but at a loop-BACK (loop_back = true, i.e.
17238        // after ≥1 `A` matched). ANTLR uses multi-token `consumeUntil(recoverSet)`
17239        // there, so two unexpected tokens before EOF are BOTH deleted and the rule
17240        // recovers (matching `(s a c c <EOF>)` for input `a c c`). Here we feed the
17241        // post-`a` state directly: `c c <EOF>` with loop_back = true.
17242        let atn = star_loop_then_eof_atn();
17243        let mut parser = mini_parser(vec![
17244            TestToken::new(2).with_text("c"),
17245            TestToken::new(2).with_text("c"),
17246            TestToken::eof("parser-test", 1, 2, 2),
17247        ]);
17248        parser.rule_context_stack = vec![RuleContextFrame {
17249            rule_index: 0,
17250            invoking_state: 0,
17251        }];
17252        let children = parser
17253            .sync_decision(&atn, 5, false, true)
17254            .expect("loop-back multi-token deletion recovers onto EOF");
17255        assert_eq!(children.len(), 2, "both `c`s deleted as error nodes");
17256        assert!(
17257            children
17258                .iter()
17259                .all(|child| parser.node(*child).kind() == NodeKind::Error)
17260        );
17261        assert_eq!(parser.number_of_syntax_errors(), 1);
17262        assert_eq!(parser.la(1), TOKEN_EOF, "EOF left for the rule's EOF match");
17263    }
17264
17265    #[test]
17266    fn sync_decision_returns_before_recovery_for_nullable_exit() {
17267        let atn = nested_star_rule_atn();
17268        for (current_context_empty, loop_back) in [(true, false), (false, true)] {
17269            let mut parser = mini_parser(vec![
17270                TestToken::new(2).with_text("c"),
17271                TestToken::new(1).with_text("a"),
17272                TestToken::eof("parser-test", 1, 2, 2),
17273            ]);
17274            parser.rule_context_stack = vec![
17275                RuleContextFrame {
17276                    rule_index: 0,
17277                    invoking_state: 0,
17278                },
17279                RuleContextFrame {
17280                    rule_index: 1,
17281                    invoking_state: 1,
17282                },
17283            ];
17284
17285            let children = parser
17286                .sync_decision(&atn, 5, current_context_empty, loop_back)
17287                .expect("nullable synchronization is a no-op");
17288
17289            assert!(children.is_empty());
17290            assert_eq!(parser.la(1), 2, "the caller must receive the current token");
17291            assert_eq!(parser.number_of_syntax_errors(), 0);
17292            assert_eq!(
17293                parser
17294                    .generated_sync_expected
17295                    .as_ref()
17296                    .expect("nullable sync preserves expected symbols")
17297                    .to_btree_set(),
17298                BTreeSet::from([TOKEN_EOF, 1])
17299            );
17300        }
17301    }
17302
17303    fn predicate_after_token_atn() -> Atn {
17304        let mut atn = ParserAtnBuilder::new(2);
17305        assert_eq!(
17306            atn.add_state(AtnStateKind::RuleStart, Some(0))
17307                .expect("state")
17308                .index(),
17309            0
17310        );
17311        assert_eq!(
17312            atn.add_state(AtnStateKind::Basic, Some(0))
17313                .expect("state")
17314                .index(),
17315            1
17316        );
17317        assert_eq!(
17318            atn.add_state(AtnStateKind::Basic, Some(0))
17319                .expect("state")
17320                .index(),
17321            2
17322        );
17323        assert_eq!(
17324            atn.add_state(AtnStateKind::Basic, Some(0))
17325                .expect("state")
17326                .index(),
17327            3
17328        );
17329        assert_eq!(
17330            atn.add_state(AtnStateKind::RuleStop, Some(0))
17331                .expect("state")
17332                .index(),
17333            4
17334        );
17335        atn.set_rule_to_start_state(vec![0])
17336            .expect("rule start states");
17337        atn.set_rule_to_stop_state(vec![4])
17338            .expect("rule stop states");
17339        atn.add_transition(
17340            0,
17341            ParserTransitionSpec::Atom {
17342                target: 1,
17343                label: 1,
17344            },
17345        )
17346        .expect("transition");
17347        atn.add_transition(
17348            1,
17349            ParserTransitionSpec::Predicate {
17350                target: 2,
17351                rule_index: 0,
17352                pred_index: 0,
17353                context_dependent: false,
17354            },
17355        )
17356        .expect("transition");
17357        atn.add_transition(
17358            2,
17359            ParserTransitionSpec::Atom {
17360                target: 3,
17361                label: 2,
17362            },
17363        )
17364        .expect("transition");
17365        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
17366            .expect("transition");
17367        finish_atn(atn)
17368    }
17369
17370    fn predicate_gated_same_lookahead_atn(pred_indexes: [usize; 2]) -> Atn {
17371        let mut atn = ParserAtnBuilder::new(1);
17372        for (state_number, kind) in [
17373            (0, AtnStateKind::RuleStart),
17374            (1, AtnStateKind::BlockStart),
17375            (2, AtnStateKind::Basic),
17376            (3, AtnStateKind::Basic),
17377            (4, AtnStateKind::Basic),
17378            (5, AtnStateKind::Basic),
17379            (6, AtnStateKind::BlockEnd),
17380            (7, AtnStateKind::RuleStop),
17381        ] {
17382            assert_eq!(
17383                atn.add_state(kind, Some(0)).expect("state").index(),
17384                state_number
17385            );
17386        }
17387        atn.set_rule_to_start_state(vec![0])
17388            .expect("rule start states");
17389        atn.set_rule_to_stop_state(vec![7])
17390            .expect("rule stop states");
17391        atn.add_decision_state(1).expect("decision state");
17392        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17393            .expect("transition");
17394        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17395            .expect("transition");
17396        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17397            .expect("transition");
17398        atn.add_transition(
17399            2,
17400            ParserTransitionSpec::Predicate {
17401                target: 4,
17402                rule_index: 0,
17403                pred_index: pred_indexes[0],
17404                context_dependent: false,
17405            },
17406        )
17407        .expect("transition");
17408        atn.add_transition(
17409            3,
17410            ParserTransitionSpec::Predicate {
17411                target: 5,
17412                rule_index: 0,
17413                pred_index: pred_indexes[1],
17414                context_dependent: false,
17415            },
17416        )
17417        .expect("transition");
17418        atn.add_transition(
17419            4,
17420            ParserTransitionSpec::Atom {
17421                target: 6,
17422                label: 1,
17423            },
17424        )
17425        .expect("transition");
17426        atn.add_transition(
17427            5,
17428            ParserTransitionSpec::Atom {
17429                target: 6,
17430                label: 1,
17431            },
17432        )
17433        .expect("transition");
17434        atn.add_transition(
17435            6,
17436            ParserTransitionSpec::Atom {
17437                target: 7,
17438                label: TOKEN_EOF,
17439            },
17440        )
17441        .expect("transition");
17442        finish_atn(atn)
17443    }
17444
17445    /// The outer decision sees helper-rule contexts `{common, extra}` and
17446    /// `{common}` after token 1. The nested decision is overridden in the
17447    /// recovery test so committed parsing can exercise token deletion after
17448    /// the outer SLL containment conflict selects alternative 1.
17449    fn context_containment_recovery_atn() -> Atn {
17450        context_containment_test_atn(
17451            Some(6),
17452            ParserTransitionSpec::Atom {
17453                target: 7,
17454                label: TOKEN_EOF,
17455            },
17456        )
17457    }
17458
17459    /// ATN for `s : A B | {false}? A C | {true}? A C;`.
17460    fn semantic_fallback_viability_atn() -> Atn {
17461        let mut atn = ParserAtnBuilder::new(3);
17462        for (state_number, kind) in [
17463            (0, AtnStateKind::RuleStart),
17464            (1, AtnStateKind::BlockStart),
17465            (2, AtnStateKind::Basic),
17466            (3, AtnStateKind::Basic),
17467            (4, AtnStateKind::Basic),
17468            (5, AtnStateKind::Basic),
17469            (6, AtnStateKind::Basic),
17470            (7, AtnStateKind::Basic),
17471            (8, AtnStateKind::Basic),
17472            (9, AtnStateKind::BlockEnd),
17473            (10, AtnStateKind::RuleStop),
17474        ] {
17475            assert_eq!(
17476                atn.add_state(kind, Some(0)).expect("state").index(),
17477                state_number
17478            );
17479        }
17480        atn.set_rule_to_start_state(vec![0])
17481            .expect("rule start states");
17482        atn.set_rule_to_stop_state(vec![10])
17483            .expect("rule stop states");
17484        atn.set_end_state(1, 9).expect("block end state");
17485        atn.add_decision_state(1).expect("decision state");
17486        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17487            .expect("entry transition");
17488        atn.add_transition(
17489            1,
17490            ParserTransitionSpec::Atom {
17491                target: 2,
17492                label: 1,
17493            },
17494        )
17495        .expect("first alternative");
17496        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17497            .expect("second alternative");
17498        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
17499            .expect("third alternative");
17500        atn.add_transition(
17501            2,
17502            ParserTransitionSpec::Atom {
17503                target: 9,
17504                label: 2,
17505            },
17506        )
17507        .expect("first alternative suffix");
17508        for (source, target, pred_index) in [(3, 4, 0), (6, 7, 1)] {
17509            atn.add_transition(
17510                source,
17511                ParserTransitionSpec::Predicate {
17512                    target,
17513                    rule_index: 0,
17514                    pred_index,
17515                    context_dependent: false,
17516                },
17517            )
17518            .expect("predicate transition");
17519        }
17520        for (source, target, label) in [(4, 5, 1), (5, 9, 3), (7, 8, 1), (8, 9, 3)] {
17521            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
17522                .expect("predicate alternative token");
17523        }
17524        atn.add_transition(
17525            9,
17526            ParserTransitionSpec::Atom {
17527                target: 10,
17528                label: TOKEN_EOF,
17529            },
17530        )
17531        .expect("EOF transition");
17532        finish_atn(atn)
17533    }
17534
17535    /// ATN for `s : gated | A; gated : {false}? A;`.
17536    fn rule_call_predicate_decision_atn() -> Atn {
17537        let mut atn = ParserAtnBuilder::new(1);
17538        for (state_number, kind, rule_index) in [
17539            (0, AtnStateKind::RuleStart, 0),
17540            (1, AtnStateKind::BlockStart, 0),
17541            (2, AtnStateKind::Basic, 0),
17542            (3, AtnStateKind::Basic, 0),
17543            (4, AtnStateKind::BlockEnd, 0),
17544            (5, AtnStateKind::RuleStop, 0),
17545            (6, AtnStateKind::RuleStart, 1),
17546            (7, AtnStateKind::Basic, 1),
17547            (8, AtnStateKind::RuleStop, 1),
17548        ] {
17549            assert_eq!(
17550                atn.add_state(kind, Some(rule_index))
17551                    .expect("state")
17552                    .index(),
17553                state_number
17554            );
17555        }
17556        atn.set_rule_to_start_state(vec![0, 6])
17557            .expect("rule start states");
17558        atn.set_rule_to_stop_state(vec![5, 8])
17559            .expect("rule stop states");
17560        atn.set_end_state(1, 4).expect("block end state");
17561        atn.add_decision_state(1).expect("decision state");
17562        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17563            .expect("entry transition");
17564        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17565            .expect("gated alternative entry");
17566        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17567            .expect("direct alternative entry");
17568        atn.add_transition(
17569            2,
17570            ParserTransitionSpec::Rule {
17571                target: 6,
17572                rule_index: 1,
17573                follow_state: 4,
17574                precedence: 0,
17575            },
17576        )
17577        .expect("gated alternative");
17578        atn.add_transition(
17579            3,
17580            ParserTransitionSpec::Atom {
17581                target: 4,
17582                label: 1,
17583            },
17584        )
17585        .expect("direct alternative");
17586        atn.add_transition(
17587            4,
17588            ParserTransitionSpec::Atom {
17589                target: 5,
17590                label: TOKEN_EOF,
17591            },
17592        )
17593        .expect("EOF transition");
17594        atn.add_transition(
17595            6,
17596            ParserTransitionSpec::Predicate {
17597                target: 7,
17598                rule_index: 1,
17599                pred_index: 0,
17600                context_dependent: false,
17601            },
17602        )
17603        .expect("callee predicate");
17604        atn.add_transition(
17605            7,
17606            ParserTransitionSpec::Atom {
17607                target: 8,
17608                label: 1,
17609            },
17610        )
17611        .expect("callee token");
17612        finish_atn(atn)
17613    }
17614
17615    /// ATN for `s : ({true}? A)* EOF;`.
17616    fn predicate_gated_star_loop_atn() -> Atn {
17617        let mut atn = ParserAtnBuilder::new(2);
17618        for (state_number, kind) in [
17619            (0, AtnStateKind::RuleStart),
17620            (1, AtnStateKind::StarLoopEntry),
17621            (2, AtnStateKind::Basic),
17622            (3, AtnStateKind::Basic),
17623            (4, AtnStateKind::StarLoopBack),
17624            (5, AtnStateKind::LoopEnd),
17625            (6, AtnStateKind::RuleStop),
17626        ] {
17627            assert_eq!(
17628                atn.add_state(kind, Some(0)).expect("state").index(),
17629                state_number
17630            );
17631        }
17632        atn.set_rule_to_start_state(vec![0])
17633            .expect("rule start states");
17634        atn.set_rule_to_stop_state(vec![6])
17635            .expect("rule stop states");
17636        atn.add_decision_state(1).expect("decision state");
17637        atn.set_loop_back_state(5, 4).expect("loop back state");
17638        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17639            .expect("entry transition");
17640        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17641            .expect("loop enter");
17642        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
17643            .expect("loop exit");
17644        atn.add_transition(
17645            2,
17646            ParserTransitionSpec::Predicate {
17647                target: 3,
17648                rule_index: 0,
17649                pred_index: 0,
17650                context_dependent: false,
17651            },
17652        )
17653        .expect("loop predicate");
17654        atn.add_transition(
17655            3,
17656            ParserTransitionSpec::Atom {
17657                target: 4,
17658                label: 1,
17659            },
17660        )
17661        .expect("loop token");
17662        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
17663            .expect("loop back");
17664        atn.add_transition(
17665            5,
17666            ParserTransitionSpec::Atom {
17667                target: 6,
17668                label: TOKEN_EOF,
17669            },
17670        )
17671        .expect("EOF transition");
17672        finish_atn(atn)
17673    }
17674
17675    fn nested_nullable_context_atn() -> Atn {
17676        let mut atn = ParserAtnBuilder::new(1);
17677        for state_number in 0..=20 {
17678            let kind = match state_number {
17679                0 | 10 | 16 => AtnStateKind::RuleStart,
17680                9 | 15 | 20 => AtnStateKind::RuleStop,
17681                _ => AtnStateKind::Basic,
17682            };
17683            let rule_index = match state_number {
17684                0..=9 => 0,
17685                10..=15 => 1,
17686                _ => 2,
17687            };
17688            assert_eq!(
17689                atn.add_state(kind, Some(rule_index))
17690                    .expect("state")
17691                    .index(),
17692                state_number
17693            );
17694        }
17695        atn.set_rule_to_start_state(vec![0, 10, 16])
17696            .expect("rule start states");
17697        atn.set_rule_to_stop_state(vec![9, 15, 20])
17698            .expect("rule stop states");
17699        atn.add_transition(
17700            1,
17701            ParserTransitionSpec::Rule {
17702                target: 10,
17703                rule_index: 1,
17704                follow_state: 8,
17705                precedence: 0,
17706            },
17707        )
17708        .expect("transition");
17709        atn.add_transition(
17710            8,
17711            ParserTransitionSpec::Atom {
17712                target: 9,
17713                label: 1,
17714            },
17715        )
17716        .expect("transition");
17717        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17718            .expect("transition");
17719        atn.add_transition(
17720            2,
17721            ParserTransitionSpec::Rule {
17722                target: 16,
17723                rule_index: 2,
17724                follow_state: 14,
17725                precedence: 0,
17726            },
17727        )
17728        .expect("transition");
17729        atn.add_transition(14, ParserTransitionSpec::Epsilon { target: 15 })
17730            .expect("transition");
17731        finish_atn(atn)
17732    }
17733
17734    fn tail_call_context_atn() -> Atn {
17735        let mut atn = ParserAtnBuilder::new(1);
17736        for (kind, rule_index) in [
17737            (AtnStateKind::RuleStart, 0),
17738            (AtnStateKind::Basic, 0),
17739            (AtnStateKind::Basic, 0),
17740            (AtnStateKind::RuleStop, 0),
17741            (AtnStateKind::RuleStart, 1),
17742            (AtnStateKind::Basic, 1),
17743            (AtnStateKind::RuleStop, 1),
17744            (AtnStateKind::RuleStart, 2),
17745            (AtnStateKind::RuleStop, 2),
17746        ] {
17747            atn.add_state(kind, Some(rule_index)).expect("state");
17748        }
17749        atn.set_rule_to_start_state(vec![0, 4, 7])
17750            .expect("rule starts");
17751        atn.set_rule_to_stop_state(vec![3, 6, 8])
17752            .expect("rule stops");
17753        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17754            .expect("outer entry");
17755        atn.add_transition(
17756            1,
17757            ParserTransitionSpec::Rule {
17758                target: 4,
17759                rule_index: 1,
17760                follow_state: 2,
17761                precedence: 0,
17762            },
17763        )
17764        .expect("non-tail outer call");
17765        atn.add_transition(
17766            2,
17767            ParserTransitionSpec::Atom {
17768                target: 3,
17769                label: 1,
17770            },
17771        )
17772        .expect("observable outer continuation");
17773        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
17774            .expect("middle entry");
17775        atn.add_transition(
17776            5,
17777            ParserTransitionSpec::Rule {
17778                target: 7,
17779                rule_index: 2,
17780                follow_state: 6,
17781                precedence: 0,
17782            },
17783        )
17784        .expect("tail middle call");
17785        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
17786            .expect("inner body");
17787        finish_atn(atn)
17788    }
17789
17790    fn generated_match_recovery_atn() -> Atn {
17791        let mut atn = ParserAtnBuilder::new(2);
17792        assert_eq!(
17793            atn.add_state(AtnStateKind::RuleStart, Some(0))
17794                .expect("state")
17795                .index(),
17796            0
17797        );
17798        assert_eq!(
17799            atn.add_state(AtnStateKind::Basic, Some(0))
17800                .expect("state")
17801                .index(),
17802            1
17803        );
17804        assert_eq!(
17805            atn.add_state(AtnStateKind::Basic, Some(0))
17806                .expect("state")
17807                .index(),
17808            2
17809        );
17810        assert_eq!(
17811            atn.add_state(AtnStateKind::RuleStop, Some(0))
17812                .expect("state")
17813                .index(),
17814            3
17815        );
17816        assert_eq!(
17817            atn.add_state(AtnStateKind::RuleStart, Some(1))
17818                .expect("state")
17819                .index(),
17820            4
17821        );
17822        assert_eq!(
17823            atn.add_state(AtnStateKind::RuleStop, Some(1))
17824                .expect("state")
17825                .index(),
17826            5
17827        );
17828        atn.set_rule_to_start_state(vec![0, 4])
17829            .expect("rule start states");
17830        atn.set_rule_to_stop_state(vec![3, 5])
17831            .expect("rule stop states");
17832        atn.add_transition(
17833            1,
17834            ParserTransitionSpec::Rule {
17835                target: 4,
17836                rule_index: 1,
17837                follow_state: 2,
17838                precedence: 0,
17839            },
17840        )
17841        .expect("transition");
17842        atn.add_transition(
17843            2,
17844            ParserTransitionSpec::Atom {
17845                target: 3,
17846                label: TOKEN_EOF,
17847            },
17848        )
17849        .expect("transition");
17850        finish_atn(atn)
17851    }
17852
17853    fn complement_set_atn() -> Atn {
17854        let mut atn = ParserAtnBuilder::new(1);
17855        assert_eq!(
17856            atn.add_state(AtnStateKind::RuleStart, Some(0))
17857                .expect("state")
17858                .index(),
17859            0
17860        );
17861        assert_eq!(
17862            atn.add_state(AtnStateKind::RuleStop, Some(0))
17863                .expect("state")
17864                .index(),
17865            1
17866        );
17867        atn.set_rule_to_start_state(vec![0])
17868            .expect("rule start states");
17869        atn.set_rule_to_stop_state(vec![1])
17870            .expect("rule stop states");
17871        let excluded = atn.add_interval_set([(1, 1)]).expect("excluded set");
17872        atn.add_transition(
17873            0,
17874            ParserTransitionSpec::NotSet {
17875                target: 1,
17876                set: excluded,
17877            },
17878        )
17879        .expect("transition");
17880        finish_atn(atn)
17881    }
17882
17883    /// ATN for `start : . EOF ;`: a wildcard whose follow state explicitly matches
17884    /// EOF. State 0 (`RuleStart`) -wildcard-> 2 -EOF-> 1 (`RuleStop`).
17885    fn wildcard_then_eof_atn() -> Atn {
17886        let mut atn = ParserAtnBuilder::new(1);
17887        assert_eq!(
17888            atn.add_state(AtnStateKind::RuleStart, Some(0))
17889                .expect("state")
17890                .index(),
17891            0
17892        );
17893        assert_eq!(
17894            atn.add_state(AtnStateKind::RuleStop, Some(0))
17895                .expect("state")
17896                .index(),
17897            1
17898        );
17899        assert_eq!(
17900            atn.add_state(AtnStateKind::Basic, Some(0))
17901                .expect("state")
17902                .index(),
17903            2
17904        );
17905        atn.set_rule_to_start_state(vec![0])
17906            .expect("rule start states");
17907        atn.set_rule_to_stop_state(vec![1])
17908            .expect("rule stop states");
17909        atn.add_transition(0, ParserTransitionSpec::Wildcard { target: 2 })
17910            .expect("transition");
17911        atn.add_transition(
17912            2,
17913            ParserTransitionSpec::Atom {
17914                target: 1,
17915                label: TOKEN_EOF,
17916            },
17917        )
17918        .expect("transition");
17919        finish_atn(atn)
17920    }
17921
17922    #[test]
17923    fn parser_matches_token_and_reports_mismatch() {
17924        let source = Source {
17925            tokens: vec![
17926                TestToken::new(1).with_text("x"),
17927                TestToken::eof("parser-test", 1, 1, 1),
17928            ],
17929            index: 0,
17930        };
17931        let data = RecognizerData::new(
17932            "Mini.g4",
17933            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17934        );
17935        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
17936        let matched = parser.match_token(1).expect("token 1 should match");
17937        assert_eq!(parser.node(matched).text(), "x");
17938        assert!(parser.match_token(1).is_err());
17939    }
17940
17941    #[test]
17942    fn parser_matches_token_sets() {
17943        let mut parser = mini_parser(vec![
17944            TestToken::new(1).with_text("x"),
17945            TestToken::eof("parser-test", 1, 1, 1),
17946        ]);
17947
17948        let matched = parser
17949            .match_set(&[(1, 1), (3, 4)])
17950            .expect("token set should match");
17951        assert_eq!(parser.node(matched).text(), "x");
17952        assert!(parser.match_not_set(&[(1, 1)], 1, 4).is_err());
17953    }
17954
17955    #[test]
17956    fn generated_rule_api_tracks_state_and_precedence() {
17957        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17958
17959        let context = parser.enter_rule(7, 2);
17960        assert_eq!(context.rule_index(), 2);
17961        assert_eq!(parser.state(), 7);
17962        assert_eq!(
17963            parser.rule_context_stack,
17964            vec![RuleContextFrame {
17965                rule_index: 2,
17966                invoking_state: 7
17967            }]
17968        );
17969
17970        let recursive = parser.enter_recursion_rule(11, 3, 4);
17971        assert_eq!(recursive.rule_index(), 3);
17972        assert!(parser.precpred(4));
17973        assert!(parser.precpred(5));
17974        assert!(!parser.precpred(3));
17975
17976        let next = parser.push_new_recursion_context(13, 3);
17977        assert_eq!(next.invoking_state(), 13);
17978        parser.unroll_recursion_context();
17979        assert_eq!(parser.precedence_stack, vec![0]);
17980        assert_eq!(
17981            parser.rule_context_stack,
17982            vec![RuleContextFrame {
17983                rule_index: 2,
17984                invoking_state: 7
17985            }]
17986        );
17987
17988        parser.exit_rule();
17989        assert!(parser.rule_context_stack.is_empty());
17990    }
17991
17992    #[test]
17993    fn reset_rewinds_input_and_clears_parser_owned_parse_state() {
17994        let mut parser = mini_parser(vec![
17995            TestToken::new(1).with_text("x"),
17996            TestToken::eof("parser-test", 1, 1, 1),
17997        ]);
17998        let matched = parser.match_token(1).expect("token should match");
17999        assert_eq!(parser.node(matched).text(), "x");
18000        parser.record_generated_syntax_error();
18001        parser.set_int_member(7, 11);
18002        parser.set_build_parse_trees(false);
18003        parser.set_report_diagnostic_errors(true);
18004        parser.set_prediction_mode(PredictionMode::Sll);
18005        parser.set_bail_on_error(true);
18006        let _context = parser.enter_recursion_rule(9, 0, 4);
18007        parser.pending_invoking_states.push(5);
18008        parser.unknown_predicate_hits.push((0, 1));
18009        parser.unhandled_action_hits.push((0, 2));
18010
18011        parser.reset();
18012
18013        assert_eq!(parser.input.index(), 0);
18014        assert_eq!(parser.la(1), 1);
18015        assert_eq!(parser.state(), -1);
18016        assert_eq!(parser.number_of_syntax_errors(), 0);
18017        assert_eq!(parser.parse_tree_storage().node_count(), 0);
18018        assert!(parser.rule_context_stack.is_empty());
18019        assert!(parser.pending_invoking_states.is_empty());
18020        assert_eq!(parser.precedence_stack, [0]);
18021        assert!(parser.unknown_predicate_hits.is_empty());
18022        assert!(parser.unhandled_action_hits.is_empty());
18023        assert_eq!(parser.int_member(7), Some(11));
18024        assert!(!parser.build_parse_trees());
18025        assert!(parser.report_diagnostic_errors());
18026        assert_eq!(parser.prediction_mode(), PredictionMode::Sll);
18027        assert!(parser.bail_on_error());
18028    }
18029
18030    #[test]
18031    fn set_token_stream_replaces_input_and_resets_parser() {
18032        let mut parser = mini_parser(vec![
18033            TestToken::new(1).with_text("old"),
18034            TestToken::eof("parser-test", 1, 1, 1),
18035        ]);
18036        parser.consume();
18037        parser.record_generated_syntax_error();
18038        let replacement = CommonTokenStream::new(Source {
18039            tokens: vec![
18040                TestToken::new(2).with_text("new"),
18041                TestToken::eof("parser-test", 1, 1, 1),
18042            ],
18043            index: 0,
18044        });
18045
18046        parser.set_token_stream(replacement);
18047
18048        assert_eq!(parser.input.index(), 0);
18049        assert_eq!(parser.la(1), 2);
18050        assert_eq!(parser.input.text_all(), "new");
18051        assert_eq!(parser.number_of_syntax_errors(), 0);
18052    }
18053
18054    #[test]
18055    fn active_invocation_states_exclude_the_root_frame() {
18056        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18057
18058        let _root = parser.enter_rule(0, 0);
18059        assert!(parser.active_invocation_states().is_empty());
18060
18061        let marker = parser.push_invoking_state(6);
18062        let _child = parser.enter_rule(2, 1);
18063        parser.discard_invoking_state(marker);
18064        assert_eq!(parser.active_invocation_states(), [6]);
18065
18066        let marker = parser.push_invoking_state(13);
18067        let _grandchild = parser.enter_rule(4, 2);
18068        parser.discard_invoking_state(marker);
18069        assert_eq!(parser.active_invocation_states(), [13, 6]);
18070
18071        parser.exit_rule();
18072        parser.exit_rule();
18073        parser.exit_rule();
18074    }
18075
18076    #[test]
18077    fn parser_predicates_support_token_adjacency() {
18078        let mut parser = mini_parser(vec![
18079            TestToken::new(1).with_text("=").with_span(0, 0),
18080            TestToken::new(1).with_text(">").with_span(1, 1),
18081            TestToken::eof("parser-test", 2, 1, 2),
18082        ]);
18083        parser.consume();
18084        parser.consume();
18085
18086        let predicates = [(0, 0, ParserPredicate::TokenPairAdjacent)];
18087
18088        assert!(parser.parser_semantic_predicate_matches(&predicates, 0, 0));
18089
18090        let mut parser = mini_parser(vec![
18091            TestToken::new(1).with_text("=").with_span(0, 0),
18092            TestToken::new(1)
18093                .with_text(" ")
18094                .with_channel(HIDDEN_CHANNEL)
18095                .with_span(1, 1),
18096            TestToken::new(1).with_text(">").with_span(2, 2),
18097            TestToken::eof("parser-test", 3, 1, 3),
18098        ]);
18099        parser.consume();
18100        parser.consume();
18101
18102        assert!(!parser.parser_semantic_predicate_matches(&predicates, 0, 0));
18103    }
18104
18105    #[test]
18106    fn parser_predicates_support_context_child_text_checks() {
18107        let mut parser = mini_parser(vec![
18108            TestToken::new(1).with_text("var"),
18109            TestToken::eof("parser-test", 1, 1, 1),
18110        ]);
18111        let mut context = ParserRuleContext::new(1, 0);
18112        let mut child_context = ParserRuleContext::new(2, 0);
18113        let terminal = parser.terminal_tree(TokenId::try_from(0).expect("test token ID"));
18114        parser.tree.add_child(&mut child_context, terminal);
18115        let child = parser.rule_node(child_context);
18116        parser.tree.add_child(&mut context, child);
18117        let predicates = [(
18118            1,
18119            0,
18120            ParserPredicate::ContextChildRuleTextNotEquals {
18121                rule_index: 2,
18122                text: "var",
18123            },
18124        )];
18125
18126        assert!(
18127            !parser.parser_semantic_predicate_matches_with_context_and_local(
18128                &predicates,
18129                1,
18130                0,
18131                &context,
18132                0,
18133            )
18134        );
18135    }
18136
18137    #[test]
18138    fn context_expected_symbols_walks_nullable_parent_contexts() {
18139        let atn = nested_nullable_context_atn();
18140        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18141        parser.rule_context_stack = vec![
18142            RuleContextFrame {
18143                rule_index: 0,
18144                invoking_state: 0,
18145            },
18146            RuleContextFrame {
18147                rule_index: 1,
18148                invoking_state: 1,
18149            },
18150            RuleContextFrame {
18151                rule_index: 2,
18152                invoking_state: 2,
18153            },
18154        ];
18155
18156        let expected = parser.context_expected_symbols(&atn);
18157
18158        assert!(expected.contains(&1));
18159        assert!(expected.contains(&TOKEN_EOF));
18160    }
18161
18162    #[test]
18163    fn prediction_context_return_states_track_rule_stack_changes() {
18164        let atn = nested_nullable_context_atn();
18165        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18166        parser.rule_context_stack = vec![
18167            RuleContextFrame {
18168                rule_index: 0,
18169                invoking_state: 0,
18170            },
18171            RuleContextFrame {
18172                rule_index: 1,
18173                invoking_state: 1,
18174            },
18175            RuleContextFrame {
18176                rule_index: 2,
18177                invoking_state: 2,
18178            },
18179        ];
18180
18181        let initial_version = parser.rule_context_version();
18182        let first: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18183        let second: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18184        assert_eq!(first, second);
18185        assert_eq!(parser.rule_context_version(), initial_version);
18186
18187        parser.exit_rule();
18188        let after_pop: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18189        assert_ne!(first, after_pop);
18190        assert_ne!(parser.rule_context_version(), initial_version);
18191    }
18192
18193    #[test]
18194    fn prediction_context_return_states_skip_tail_call_frames() {
18195        let atn = tail_call_context_atn();
18196        assert!(
18197            atn.state(5)
18198                .expect("tail call source")
18199                .transitions()
18200                .first()
18201                .expect("tail call")
18202                .is_tail_call()
18203        );
18204        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18205        parser.rule_context_stack = vec![
18206            RuleContextFrame {
18207                rule_index: 0,
18208                invoking_state: 0,
18209            },
18210            RuleContextFrame {
18211                rule_index: 1,
18212                invoking_state: 1,
18213            },
18214            RuleContextFrame {
18215                rule_index: 2,
18216                invoking_state: 5,
18217            },
18218        ];
18219
18220        assert_eq!(
18221            parser
18222                .prediction_context_return_states(&atn)
18223                .collect::<Vec<_>>(),
18224            [2]
18225        );
18226    }
18227
18228    #[test]
18229    fn generated_match_token_recovers_missing_token_from_context_follow() {
18230        let atn = generated_match_recovery_atn();
18231        let data = RecognizerData::new(
18232            "Mini.g4",
18233            Vocabulary::new(
18234                [None, Some("'X'"), Some("'Y'")],
18235                [None, Some("X"), Some("Y")],
18236                [None::<&str>, None, None],
18237            ),
18238        );
18239        let mut parser = BaseParser::new(
18240            CommonTokenStream::new(Source {
18241                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
18242                index: 0,
18243            }),
18244            data,
18245        );
18246        parser.rule_context_stack = vec![
18247            RuleContextFrame {
18248                rule_index: 0,
18249                invoking_state: 0,
18250            },
18251            RuleContextFrame {
18252                rule_index: 1,
18253                invoking_state: 1,
18254            },
18255        ];
18256        assert_eq!(parser.number_of_syntax_errors(), 0);
18257
18258        let node = parser
18259            .match_token_recovering(2, 5, &atn)
18260            .expect("generated match should insert missing token");
18261
18262        assert_eq!(node.children().len(), 1);
18263        assert_eq!(parser.node(node.children()[0]).text(), "<missing 'Y'>");
18264        assert_eq!(
18265            node.clone()
18266                .into_child_iter()
18267                .map(|child| parser.node(child).text())
18268                .collect::<Vec<_>>(),
18269            ["<missing 'Y'>"]
18270        );
18271        // Single-token insertion synthesizes a missing token and consumes nothing,
18272        // so no EOF terminal is consumed even though lookahead is EOF.
18273        assert!(!node.consumed_eof());
18274        assert_eq!(parser.la(1), TOKEN_EOF);
18275        assert_eq!(parser.number_of_syntax_errors(), 1);
18276        assert_eq!(
18277            parser.generated_parser_diagnostics,
18278            [ParserDiagnostic {
18279                line: 1,
18280                column: 3,
18281                message: "missing 'Y' at '<EOF>'".to_owned(),
18282                offending: parser.input.lt_id(1),
18283            }]
18284        );
18285    }
18286
18287    #[test]
18288    fn generated_match_token_counts_single_token_deletion_recovery() {
18289        let atn = generated_match_recovery_atn();
18290        let data = RecognizerData::new(
18291            "Mini.g4",
18292            Vocabulary::new(
18293                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18294                [None, Some("X"), Some("Y"), Some("Z")],
18295                [None::<&str>, None, None, None],
18296            ),
18297        );
18298        let mut parser = BaseParser::new(
18299            CommonTokenStream::new(Source {
18300                tokens: vec![
18301                    TestToken::new(3).with_text("z"),
18302                    TestToken::new(2).with_text("y"),
18303                    TestToken::eof("parser-test", 3, 1, 3),
18304                ],
18305                index: 0,
18306            }),
18307            data,
18308        );
18309
18310        let node = parser
18311            .match_token_recovering(2, 5, &atn)
18312            .expect("generated match should delete the extraneous token");
18313
18314        assert_eq!(node.children().len(), 2);
18315        assert_eq!(parser.node(node.children()[0]).kind(), NodeKind::Error);
18316        assert_eq!(parser.node(node.children()[0]).text(), "z");
18317        assert_eq!(parser.node(node.children()[1]).text(), "y");
18318        assert_eq!(
18319            node.into_child_iter()
18320                .map(|child| parser.node(child).text())
18321                .collect::<Vec<_>>(),
18322            ["z", "y"]
18323        );
18324        assert_eq!(parser.number_of_syntax_errors(), 1);
18325    }
18326
18327    #[test]
18328    fn generated_match_token_iterates_single_success_without_a_children_vec() {
18329        let atn = generated_match_recovery_atn();
18330        let data = RecognizerData::new(
18331            "Mini.g4",
18332            Vocabulary::new(
18333                [None, Some("'X'"), Some("'Y'")],
18334                [None, Some("X"), Some("Y")],
18335                [None::<&str>, None, None],
18336            ),
18337        );
18338        let mut parser = BaseParser::new(
18339            CommonTokenStream::new(Source {
18340                tokens: vec![
18341                    TestToken::new(2).with_text("y"),
18342                    TestToken::eof("parser-test", 1, 1, 1),
18343                ],
18344                index: 0,
18345            }),
18346            data,
18347        );
18348
18349        let node = parser
18350            .match_token_recovering(2, 5, &atn)
18351            .expect("generated match should consume the expected token");
18352
18353        assert_eq!(
18354            node.into_child_iter()
18355                .map(|child| parser.node(child).text())
18356                .collect::<Vec<_>>(),
18357            ["y"]
18358        );
18359        assert_eq!(parser.number_of_syntax_errors(), 0);
18360    }
18361
18362    #[test]
18363    fn generated_diagnostic_restore_rolls_back_syntax_error_count() {
18364        let atn = generated_match_recovery_atn();
18365        let data = RecognizerData::new(
18366            "Mini.g4",
18367            Vocabulary::new(
18368                [None, Some("'X'"), Some("'Y'")],
18369                [None, Some("X"), Some("Y")],
18370                [None::<&str>, None, None],
18371            ),
18372        );
18373        let mut parser = BaseParser::new(
18374            CommonTokenStream::new(Source {
18375                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
18376                index: 0,
18377            }),
18378            data,
18379        );
18380        parser.rule_context_stack = vec![
18381            RuleContextFrame {
18382                rule_index: 0,
18383                invoking_state: 0,
18384            },
18385            RuleContextFrame {
18386                rule_index: 1,
18387                invoking_state: 1,
18388            },
18389        ];
18390        let marker = parser.generated_diagnostics_checkpoint();
18391
18392        let _ = parser
18393            .match_token_recovering(2, 5, &atn)
18394            .expect("generated match should insert missing token");
18395        assert_eq!(parser.number_of_syntax_errors(), 1);
18396
18397        parser.restore_generated_diagnostics(marker);
18398
18399        assert_eq!(parser.number_of_syntax_errors(), 0);
18400        assert!(parser.generated_parser_diagnostics.is_empty());
18401    }
18402
18403    #[test]
18404    fn generated_prediction_diagnostics_use_adaptive_context() {
18405        let atn = two_alt_decision_atn();
18406        let data = RecognizerData::new(
18407            "Mini.g4",
18408            Vocabulary::new(
18409                [None, Some("'x'"), Some("'y'")],
18410                [None, Some("X"), Some("Y")],
18411                [None::<&str>, None, None],
18412            ),
18413        )
18414        .with_rule_names(["s"]);
18415        let mut parser = BaseParser::new(
18416            CommonTokenStream::new(Source {
18417                tokens: vec![
18418                    TestToken::new(1)
18419                        .with_text("x")
18420                        .with_position(1, 0)
18421                        .with_span(0, 0),
18422                    TestToken::new(2)
18423                        .with_text("y")
18424                        .with_position(1, 2)
18425                        .with_span(1, 1),
18426                    TestToken::eof("parser-test", 2, 1, 3),
18427                ],
18428                index: 0,
18429            }),
18430            data,
18431        );
18432        parser.set_report_diagnostic_errors(true);
18433
18434        parser.record_generated_prediction_diagnostic(
18435            &atn,
18436            1,
18437            &ParserAtnPrediction {
18438                alt: 1,
18439                requires_full_context: true,
18440                has_semantic_context: false,
18441                diagnostic: Some(ParserAtnPredictionDiagnostic {
18442                    kind: ParserAtnPredictionDiagnosticKind::ContextSensitivity,
18443                    start_index: 0,
18444                    sll_stop_index: 1,
18445                    ll_stop_index: 0,
18446                    conflicting_alts: vec![1, 2],
18447                    exact: false,
18448                }),
18449            },
18450        );
18451        // Ambiguities from the default LL prediction mode are non-exact, so —
18452        // matching Java's exactOnly DiagnosticErrorListener — only the
18453        // attempting-full-context line is reported. Exact-ambiguity mode
18454        // reports the ambiguity itself.
18455        parser.record_generated_prediction_diagnostic(
18456            &atn,
18457            1,
18458            &ParserAtnPrediction {
18459                alt: 1,
18460                requires_full_context: true,
18461                has_semantic_context: false,
18462                diagnostic: Some(ParserAtnPredictionDiagnostic {
18463                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18464                    start_index: 0,
18465                    sll_stop_index: 1,
18466                    ll_stop_index: 1,
18467                    conflicting_alts: vec![1, 2],
18468                    exact: false,
18469                }),
18470            },
18471        );
18472
18473        // The full-context/context-sensitivity diagnostic trace (order + decision + input windows)
18474        // is one snapshot rather than three ParserDiagnostic literals.
18475        insta::assert_debug_snapshot!(
18476            "generated_prediction_diagnostics_use_adaptive_context",
18477            parser.generated_parser_diagnostics
18478        );
18479    }
18480
18481    #[test]
18482    fn sll_mode_suppresses_exact_conflict_diagnostics() {
18483        let atn = two_alt_decision_atn();
18484        let mut parser = mini_parser(vec![
18485            TestToken::new(1).with_text("x"),
18486            TestToken::eof("parser-test", 1, 1, 1),
18487        ]);
18488        parser.set_prediction_mode(PredictionMode::Sll);
18489        parser.set_report_diagnostic_errors(true);
18490
18491        parser.record_generated_prediction_diagnostic(
18492            &atn,
18493            1,
18494            &ParserAtnPrediction {
18495                alt: 1,
18496                requires_full_context: false,
18497                has_semantic_context: false,
18498                diagnostic: Some(ParserAtnPredictionDiagnostic {
18499                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18500                    start_index: 0,
18501                    sll_stop_index: 0,
18502                    ll_stop_index: 0,
18503                    conflicting_alts: vec![1, 2],
18504                    exact: true,
18505                }),
18506            },
18507        );
18508
18509        assert!(parser.generated_parser_diagnostics.is_empty());
18510    }
18511
18512    #[test]
18513    fn local_exact_conflict_reports_ambiguity_without_full_context_attempt() {
18514        let atn = two_alt_decision_atn();
18515        let mut parser = mini_parser(vec![
18516            TestToken::new(1).with_text("x"),
18517            TestToken::eof("parser-test", 1, 1, 1),
18518        ]);
18519        parser.set_report_diagnostic_errors(true);
18520
18521        parser.record_generated_prediction_diagnostic(
18522            &atn,
18523            1,
18524            &ParserAtnPrediction {
18525                alt: 1,
18526                requires_full_context: false,
18527                has_semantic_context: false,
18528                diagnostic: Some(ParserAtnPredictionDiagnostic {
18529                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18530                    start_index: 0,
18531                    sll_stop_index: 0,
18532                    ll_stop_index: 0,
18533                    conflicting_alts: vec![1, 2],
18534                    exact: true,
18535                }),
18536            },
18537        );
18538
18539        insta::assert_debug_snapshot!(
18540            "local_exact_conflict_reports_ambiguity_without_full_context_attempt",
18541            parser.generated_parser_diagnostics
18542        );
18543    }
18544
18545    #[test]
18546    fn full_context_exact_conflict_reports_attempt_and_ambiguity() {
18547        let atn = two_alt_decision_atn();
18548        let mut parser = mini_parser(vec![
18549            TestToken::new(1).with_text("x"),
18550            TestToken::new(2).with_text("y"),
18551            TestToken::eof("parser-test", 2, 1, 2),
18552        ]);
18553        parser.set_report_diagnostic_errors(true);
18554
18555        parser.record_generated_prediction_diagnostic(
18556            &atn,
18557            1,
18558            &ParserAtnPrediction {
18559                alt: 1,
18560                requires_full_context: true,
18561                has_semantic_context: false,
18562                diagnostic: Some(ParserAtnPredictionDiagnostic {
18563                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18564                    start_index: 0,
18565                    sll_stop_index: 0,
18566                    ll_stop_index: 1,
18567                    conflicting_alts: vec![1, 2],
18568                    exact: true,
18569                }),
18570            },
18571        );
18572
18573        insta::assert_debug_snapshot!(
18574            "full_context_exact_conflict_reports_attempt_and_ambiguity",
18575            parser.generated_parser_diagnostics
18576        );
18577    }
18578
18579    #[test]
18580    fn generated_match_not_set_recovers_empty_complement_at_eof() {
18581        let atn = complement_set_atn();
18582        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18583        parser.rule_context_stack = vec![RuleContextFrame {
18584            rule_index: 0,
18585            invoking_state: 0,
18586        }];
18587
18588        let node = parser
18589            .match_not_token_set_recovering(
18590                atn.token_set(0).expect("excluded token set"),
18591                1,
18592                1,
18593                1,
18594                &atn,
18595            )
18596            .expect("empty complement should recover at EOF");
18597
18598        assert_eq!(node.children().len(), 1);
18599        // Recovery synthesizes a missing token without consuming EOF, so the
18600        // enclosing rule must not record EOF as its stop token.
18601        assert!(!node.consumed_eof());
18602        assert_eq!(parser.la(1), TOKEN_EOF);
18603        assert_eq!(
18604            parser.generated_parser_diagnostics,
18605            [ParserDiagnostic {
18606                line: 1,
18607                column: 1,
18608                message: "missing {} at '<EOF>'".to_owned(),
18609                offending: parser.input.lt_id(1),
18610            }]
18611        );
18612    }
18613
18614    #[test]
18615    fn wildcard_recovers_via_insertion_when_follow_expects_eof_at_eof() {
18616        // `start : . EOF ;` on empty input. The wildcard is modeled as an
18617        // empty-complement not-set; at EOF the follow state (the explicit EOF
18618        // match) expects EOF, so even in the start rule recovery must perform
18619        // single-token insertion (`<missing ...>`) rather than aborting — matching
18620        // ANTLR's `(start <missing ...> <EOF>)` / "missing ... at '<EOF>'".
18621        let atn = wildcard_then_eof_atn();
18622        let data = RecognizerData::new(
18623            "Mini.g4",
18624            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
18625        );
18626        let mut parser = BaseParser::new(
18627            CommonTokenStream::new(Source {
18628                tokens: vec![TestToken::eof("parser-test", 1, 1, 1)],
18629                index: 0,
18630            }),
18631            data,
18632        );
18633        parser.rule_context_stack = vec![RuleContextFrame {
18634            rule_index: 0,
18635            invoking_state: 0,
18636        }];
18637
18638        let node = parser
18639            .match_not_set_recovering(&[], 1, atn.max_token_type(), 2, &atn)
18640            .expect("wildcard at EOF should recover by insertion when follow expects EOF");
18641
18642        // A single `<missing ...>` error node is inserted; EOF is not consumed.
18643        assert_eq!(node.children().len(), 1);
18644        assert!(!node.consumed_eof());
18645        assert!(
18646            parser
18647                .node(node.children()[0])
18648                .text()
18649                .starts_with("<missing")
18650        );
18651        assert_eq!(parser.la(1), TOKEN_EOF);
18652        assert_eq!(
18653            parser.generated_parser_diagnostics,
18654            [ParserDiagnostic {
18655                line: 1,
18656                column: 1,
18657                message: "missing 'x' at '<EOF>'".to_owned(),
18658                offending: parser.input.lt_id(1),
18659            }]
18660        );
18661    }
18662
18663    #[test]
18664    fn generated_rule_recovery_consumes_to_parent_follow() {
18665        let atn = generated_match_recovery_atn();
18666        let data = RecognizerData::new(
18667            "Mini.g4",
18668            Vocabulary::new(
18669                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18670                [None, Some("X"), Some("Y"), Some("Z")],
18671                [None::<&str>, None, None, None],
18672            ),
18673        );
18674        let mut parser = BaseParser::new(
18675            CommonTokenStream::new(Source {
18676                tokens: vec![
18677                    TestToken::new(3).with_text("z"),
18678                    TestToken::eof("parser-test", 1, 1, 1),
18679                ],
18680                index: 0,
18681            }),
18682            data,
18683        );
18684        let _parent = parser.enter_rule(0, 0);
18685        let marker = parser.push_invoking_state(1);
18686        let mut child = parser.enter_rule(4, 1);
18687        parser.discard_invoking_state(marker);
18688
18689        // The anchor recorded where the error was built must survive into the
18690        // dispatched diagnostic even though recovery consumes past it below.
18691        let offending = parser.input.lt_id(1);
18692        assert!(offending.is_some(), "the 'z' token should be buffered");
18693        parser.recover_generated_rule(
18694            &mut child,
18695            &atn,
18696            AntlrError::ParserError {
18697                line: 1,
18698                column: 0,
18699                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18700                offending,
18701            },
18702        );
18703        let tree = parser.finish_rule(child, false);
18704
18705        assert_eq!(parser.la(1), TOKEN_EOF);
18706        assert_eq!(
18707            parser.node(tree).to_string_tree_with_names(&["s", "a"]),
18708            "(a z)"
18709        );
18710        assert_eq!(parser.number_of_syntax_errors(), 1);
18711        assert_eq!(
18712            parser.generated_parser_diagnostics,
18713            [ParserDiagnostic {
18714                line: 1,
18715                column: 0,
18716                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18717                offending,
18718            }]
18719        );
18720        parser.exit_rule();
18721    }
18722
18723    #[test]
18724    fn generated_rule_recovery_forces_progress_after_repeated_error_state() {
18725        let atn = nested_nullable_context_atn();
18726        let mut parser = mini_parser(vec![
18727            TestToken::new(1).with_text("x"),
18728            TestToken::eof("parser-test", 1, 1, 1),
18729        ]);
18730        parser.rule_context_stack = vec![
18731            RuleContextFrame {
18732                rule_index: 0,
18733                invoking_state: 0,
18734            },
18735            RuleContextFrame {
18736                rule_index: 1,
18737                invoking_state: 1,
18738            },
18739            RuleContextFrame {
18740                rule_index: 2,
18741                invoking_state: 2,
18742            },
18743        ];
18744        parser.set_state(20);
18745        let mut context = ParserRuleContext::new(2, 2);
18746
18747        parser.recover_generated_rule(
18748            &mut context,
18749            &atn,
18750            AntlrError::NoViableAlternative {
18751                input: "'x'".to_owned(),
18752            },
18753        );
18754        assert_eq!(parser.input.index(), 0);
18755
18756        parser.set_state(21);
18757        parser.recover_generated_rule(
18758            &mut context,
18759            &atn,
18760            AntlrError::NoViableAlternative {
18761                input: "'x'".to_owned(),
18762            },
18763        );
18764        assert_eq!(parser.input.index(), 0);
18765        assert_eq!(
18766            parser.generated_recovery_error_states,
18767            BTreeSet::from([20, 21])
18768        );
18769
18770        parser.set_state(20);
18771        parser.recover_generated_rule(
18772            &mut context,
18773            &atn,
18774            AntlrError::NoViableAlternative {
18775                input: "'x'".to_owned(),
18776            },
18777        );
18778
18779        assert_eq!(parser.input.index(), 1);
18780        assert_eq!(parser.la(1), TOKEN_EOF);
18781        assert!(context.has_matched_child());
18782        assert_eq!(parser.generated_recovery_error_states, BTreeSet::from([20]));
18783
18784        parser.match_eof().expect("EOF should match");
18785        assert_eq!(parser.generated_recovery_error_index, None);
18786        assert!(parser.generated_recovery_error_states.is_empty());
18787    }
18788
18789    #[test]
18790    fn greedy_ll1_alt_handles_nullable_loop_exit() {
18791        let mut body_symbols = TokenBitSet::default();
18792        body_symbols.insert(1);
18793        let entry = DecisionLookahead {
18794            transitions: vec![
18795                TransitionLookSet {
18796                    symbols: body_symbols,
18797                    nullable: false,
18798                },
18799                TransitionLookSet {
18800                    symbols: TokenBitSet::default(),
18801                    nullable: true,
18802                },
18803            ],
18804        };
18805
18806        assert_eq!(ll1_unique_alt(&entry, 2), None);
18807        assert_eq!(ll1_greedy_alt(&entry, 2, false), Some(1));
18808        assert_eq!(ll1_greedy_alt(&entry, 1, false), None);
18809        assert_eq!(ll1_greedy_alt(&entry, 1, true), None);
18810    }
18811
18812    #[test]
18813    fn ordinary_repetition_builds_tree_in_input_order() {
18814        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18815            let mut parser = mini_parser(repeated_x_tokens(3));
18816            let tree = parser
18817                .parse_atn_rule(&atn, 0)
18818                .expect("ordinary repetition should parse");
18819
18820            let root = parser
18821                .node(tree)
18822                .as_rule()
18823                .expect("entry result should be a rule");
18824            let body_rules = root.child_rules(1).collect::<Vec<_>>();
18825            assert_eq!(root.text(), "xxx<EOF>");
18826            assert_eq!(body_rules.len(), 3);
18827            assert_eq!(
18828                body_rules
18829                    .iter()
18830                    .map(|rule| rule.start_id().expect("body start").index())
18831                    .collect::<Vec<_>>(),
18832                [0, 1, 2]
18833            );
18834            assert_eq!(
18835                body_rules
18836                    .iter()
18837                    .map(|rule| rule.stop_id().expect("body stop").index())
18838                    .collect::<Vec<_>>(),
18839                [0, 1, 2]
18840            );
18841            assert_eq!(parser.number_of_syntax_errors(), 0);
18842        }
18843    }
18844
18845    #[test]
18846    fn deeply_nested_deferred_rules_materialize_on_small_stack() {
18847        const DEPTH: usize = 20_000;
18848
18849        std::thread::Builder::new()
18850            .name("deferred-rule-materialization".to_owned())
18851            .stack_size(256 * 1024)
18852            .spawn(|| {
18853                let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
18854                let mut root = FastDeferredNodeId::EMPTY;
18855                for depth in 0..DEPTH {
18856                    root = parser
18857                        .recognition_arena
18858                        .deferred_rule_node(FastDeferredRule {
18859                            rule_index: u32::try_from(depth).expect("depth fits in u32"),
18860                            invoking_state: i32::try_from(depth).expect("depth fits in i32"),
18861                            start_index: 0,
18862                            stop_index: None,
18863                            deferred_children: root,
18864                            children: NodeSeqId::EMPTY,
18865                        });
18866                }
18867
18868                let (mut children, alt_number) =
18869                    parser.materialize_fast_deferred_nodes(root, NodeSeqId::EMPTY);
18870                assert_eq!(alt_number, 0);
18871                for expected_rule in (0..DEPTH).rev() {
18872                    let mut nodes = parser.recognition_arena.iter(children);
18873                    let node = nodes.next().expect("nested rule node");
18874                    assert!(nodes.next().is_none(), "each rule has one child");
18875                    let ArenaRecognizedNode::Rule {
18876                        rule_index,
18877                        children: nested,
18878                        ..
18879                    } = parser.recognition_arena.node(node)
18880                    else {
18881                        panic!("expected nested rule");
18882                    };
18883                    assert_eq!(rule_index as usize, expected_rule);
18884                    children = nested;
18885                }
18886                assert!(children.is_empty());
18887            })
18888            .expect("small-stack thread should start")
18889            .join()
18890            .expect("deferred rules should materialize without recursion");
18891    }
18892
18893    #[test]
18894    fn deferred_alternatives_preserve_left_recursive_contexts() {
18895        let mut parser = mini_parser(vec![
18896            TestToken::new(1).with_text("1"),
18897            TestToken::new(2).with_text("+"),
18898            TestToken::new(1).with_text("2"),
18899            TestToken::eof("parser-test", 3, 1, 3),
18900        ]);
18901        let base = parser.arena_token_node(0, false);
18902        let operator = parser.arena_token_node(1, false);
18903        let right = parser.arena_token_node(2, false);
18904
18905        let base = parser.recognition_arena.prepend(NodeSeqId::EMPTY, base);
18906        let base = parser.recognition_arena.deferred_fragment(base);
18907        let operator = parser.recognition_arena.prepend(NodeSeqId::EMPTY, operator);
18908        let operator = parser.recognition_arena.deferred_fragment(operator);
18909        let right = parser.recognition_arena.prepend(NodeSeqId::EMPTY, right);
18910        let right = parser.recognition_arena.deferred_fragment(right);
18911        let base_alt = parser.recognition_arena.deferred_alternative(1);
18912        let boundary = parser.recognition_arena.deferred_left_recursive_boundary(0);
18913        let operator_alt = parser.recognition_arena.deferred_alternative(6);
18914
18915        let mut deferred = FastDeferredNodeId::EMPTY;
18916        for fragment in [base_alt, base, boundary, operator_alt, operator, right] {
18917            deferred = parser
18918                .recognition_arena
18919                .concat_deferred_nodes(deferred, fragment);
18920        }
18921        let (nodes, root_alt_number) =
18922            parser.materialize_fast_deferred_nodes(deferred, NodeSeqId::EMPTY);
18923        let nodes = parser
18924            .recognition_arena
18925            .fold_left_recursive_boundaries(nodes);
18926
18927        let mut root = ParserRuleContext::new(0, -1);
18928        root.set_context_alt_number(root_alt_number);
18929        let mut cursor = nodes;
18930        while let Some(link) = parser.recognition_arena.link(cursor) {
18931            let child = parser
18932                .arena_recognized_node_tree(link.head, false, true)
18933                .expect("materialized child should become a public tree");
18934            parser.tree.add_child(&mut root, child);
18935            cursor = link.tail;
18936        }
18937        let tree = parser.rule_node(root);
18938        let contexts = parser
18939            .node(tree)
18940            .descendants()
18941            .filter_map(Node::as_rule)
18942            .map(|rule| {
18943                (
18944                    rule.rule_index(),
18945                    rule.alt_number(),
18946                    rule.context_alt_number(),
18947                    rule.text(),
18948                )
18949            })
18950            .collect::<Vec<_>>();
18951
18952        insta::assert_debug_snapshot!(
18953            "deferred_alternatives_preserve_left_recursive_contexts",
18954            contexts
18955        );
18956    }
18957
18958    #[test]
18959    fn fast_recognizer_preserves_labeled_left_recursive_operator_context() {
18960        let atn = labeled_left_recursive_operator_atn();
18961        let mut parser = mini_parser(vec![
18962            TestToken::new(1).with_text("a"),
18963            TestToken::new(3).with_text("+"),
18964            TestToken::new(1).with_text("b"),
18965            TestToken::eof("parser-test", 3, 1, 3),
18966        ]);
18967
18968        let (tree, _) = parser
18969            .parse_atn_rule_with_runtime_options(
18970                &atn,
18971                0,
18972                ParserRuntimeOptions {
18973                    track_context_alt_numbers: true,
18974                    ..ParserRuntimeOptions::default()
18975                },
18976            )
18977            .expect("labeled left-recursive addition should parse");
18978        let contexts = parser
18979            .node(tree)
18980            .descendants()
18981            .filter_map(Node::as_rule)
18982            .map(|rule| {
18983                let operator = rule
18984                    .children()
18985                    .next()
18986                    .and_then(Node::as_rule)
18987                    .is_some_and(|child| child.rule_index() == rule.rule_index());
18988                (operator, rule.context_alt_number(), rule.text())
18989            })
18990            .collect::<Vec<_>>();
18991
18992        insta::assert_debug_snapshot!(
18993            "fast_recognizer_preserves_labeled_left_recursive_operator_context",
18994            contexts
18995        );
18996        assert!(!parser.recognition_arena.deferred_nodes.is_empty());
18997        assert_eq!(parser.number_of_syntax_errors(), 0);
18998    }
18999
19000    #[test]
19001    fn deeply_nested_rule_calls_grow_the_stack() {
19002        const DEPTH: usize = 4_096;
19003        const STACK_SIZE: usize = 256 * 1024;
19004        let atn = nested_rule_chain_atn(DEPTH);
19005        std::thread::Builder::new()
19006            .name("nested-adaptive-set-rules".to_owned())
19007            .stack_size(STACK_SIZE)
19008            .spawn(move || {
19009                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
19010                parser.set_build_parse_trees(false);
19011                // This test isolates recognizer depth from the separately
19012                // cached FIRST-set metadata walk.
19013                parser.fast_first_set_prefilter = false;
19014                parser
19015                    .parse_atn_rule(&atn, 0)
19016                    .expect("nested rule chain should grow the native stack");
19017                assert_eq!(parser.input.index(), 1);
19018            })
19019            .expect("small-stack thread should start")
19020            .join()
19021            .expect("nested rule chain should not overflow its stack");
19022    }
19023
19024    #[test]
19025    fn deeply_nested_branching_rules_grow_the_stack() {
19026        const DEPTH: usize = 4_096;
19027        const STACK_SIZE: usize = 256 * 1024;
19028        let atn = nested_rule_graph_atn(DEPTH, true, false);
19029        std::thread::Builder::new()
19030            .name("nested-branching-rules".to_owned())
19031            .stack_size(STACK_SIZE)
19032            .spawn(move || {
19033                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
19034                parser.set_build_parse_trees(false);
19035                parser
19036                    .parse_atn_rule(&atn, 0)
19037                    .expect("branching rule chain should grow the native stack");
19038                assert_eq!(parser.input.index(), 1);
19039            })
19040            .expect("small-stack thread should start")
19041            .join()
19042            .expect("branching rule chain should not overflow its stack");
19043    }
19044
19045    #[test]
19046    fn deeply_nested_rule_follows_grow_the_stack() {
19047        const DEPTH: usize = 4_096;
19048        const STACK_SIZE: usize = 256 * 1024;
19049        let atn = nested_rule_graph_atn(DEPTH, false, true);
19050        std::thread::Builder::new()
19051            .name("nested-rule-follows".to_owned())
19052            .stack_size(STACK_SIZE)
19053            .spawn(move || {
19054                let mut parser = mini_parser(repeated_x_tokens(DEPTH));
19055                parser.set_build_parse_trees(false);
19056                parser.fast_first_set_prefilter = false;
19057                parser
19058                    .parse_atn_rule(&atn, 0)
19059                    .expect("rule follow chain should grow the native stack");
19060                assert_eq!(parser.input.index(), DEPTH);
19061            })
19062            .expect("small-stack thread should start")
19063            .join()
19064            .expect("nested rule follow chain should not overflow its stack");
19065    }
19066
19067    #[test]
19068    fn deeply_nested_recovery_grows_the_stack() {
19069        const DEPTH: usize = 4_096;
19070        const STACK_SIZE: usize = 256 * 1024;
19071        let atn = nested_rule_chain_atn(DEPTH);
19072        std::thread::Builder::new()
19073            .name("nested-rule-recovery".to_owned())
19074            .stack_size(STACK_SIZE)
19075            .spawn(move || {
19076                let mut parser = mini_parser(vec![
19077                    TestToken::new(2).with_text("z"),
19078                    TestToken::new(1).with_text("x"),
19079                    TestToken::eof("parser-test", 2, 1, 2),
19080                ]);
19081                parser.set_build_parse_trees(false);
19082                parser.fast_first_set_prefilter = false;
19083                parser
19084                    .parse_atn_rule(&atn, 0)
19085                    .expect("nested recovery should grow the native stack");
19086                assert_eq!(parser.input.index(), 2);
19087                assert_eq!(parser.number_of_syntax_errors(), 1);
19088            })
19089            .expect("small-stack thread should start")
19090            .join()
19091            .expect("nested rule recovery should not overflow its stack");
19092    }
19093
19094    #[test]
19095    fn ambiguous_ordinary_repetition_merges_equivalent_coordinates() {
19096        const REPETITIONS: usize = 64;
19097
19098        let atn = ambiguous_ordinary_star_loop_atn();
19099        let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
19100        let tree = parser
19101            .parse_atn_rule(&atn, 0)
19102            .expect("ambiguous ordinary repetition should parse");
19103
19104        let root = parser
19105            .node(tree)
19106            .as_rule()
19107            .expect("entry result should be a rule");
19108        assert_eq!(root.text(), format!("{}<EOF>", "x".repeat(REPETITIONS)));
19109        assert_eq!(parser.input.index(), REPETITIONS);
19110        assert!(
19111            parser.recognition_arena.deferred_nodes.len() <= REPETITIONS * 8,
19112            "equivalent segmentations should keep deferred storage linear"
19113        );
19114        assert_eq!(parser.number_of_syntax_errors(), 0);
19115    }
19116
19117    #[test]
19118    fn long_ordinary_repetition_does_not_consume_native_stack() {
19119        const REPETITIONS: usize = 20_000;
19120
19121        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
19122            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
19123            parser.set_build_parse_trees(false);
19124            parser
19125                .parse_atn_rule(&atn, 0)
19126                .expect("long ordinary repetition should parse");
19127
19128            assert_eq!(parser.input.index(), REPETITIONS);
19129            assert_eq!(parser.number_of_syntax_errors(), 0);
19130        }
19131    }
19132
19133    #[test]
19134    fn long_rule_repetition_materializes_tree_with_linear_arena_growth() {
19135        const REPETITIONS: usize = 2_000;
19136        let expected_text = format!("{}<EOF>", "x".repeat(REPETITIONS));
19137
19138        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
19139            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
19140            let tree = parser
19141                .parse_atn_rule(&atn, 0)
19142                .expect("long rule repetition should parse");
19143
19144            let root = parser
19145                .node(tree)
19146                .as_rule()
19147                .expect("entry result should be a rule");
19148            assert_eq!(root.text(), expected_text);
19149            assert_eq!(root.child_rules(1).count(), REPETITIONS);
19150            let first_body = root.child_rules(1).next().expect("first body rule");
19151            let last_body = root.child_rules(1).next_back().expect("last body rule");
19152            assert_eq!(first_body.start_id().expect("first body start").index(), 0);
19153            assert_eq!(
19154                last_body.stop_id().expect("last body stop").index(),
19155                REPETITIONS - 1
19156            );
19157
19158            let stats = parser.recognition_arena_stats();
19159            assert_eq!(
19160                (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
19161                (REPETITIONS, REPETITIONS, 0)
19162            );
19163            assert_eq!(
19164                (stats.total_links, stats.live_links, stats.dead_links),
19165                (REPETITIONS, REPETITIONS, 0)
19166            );
19167            assert_eq!(parser.recognition_arena.deferred_rules.len(), REPETITIONS);
19168            assert_eq!(
19169                parser.recognition_arena.deferred_nodes.len(),
19170                REPETITIONS * 2 - 1
19171            );
19172            assert_eq!(parser.number_of_syntax_errors(), 0);
19173        }
19174    }
19175
19176    #[test]
19177    fn clean_memo_probe_selects_sparse_promote_and_reprobe_modes() {
19178        let key = |state_number| FastRecognizeKey {
19179            state_number,
19180            stop_state: 10,
19181            index: state_number,
19182            rule_start_index: 0,
19183            decision_start_index: None,
19184            precedence: 0,
19185            recovery_symbols_id: 0,
19186            recovery_state: None,
19187        };
19188
19189        let mut sparse = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
19190        for state_number in 0..(CLEAN_MEMO_PROBE_LIMIT - 1) {
19191            assert!(sparse.clean_memo_enabled_for_key(&key(state_number)));
19192        }
19193        assert!(!sparse.clean_memo_enabled_for_key(&key(CLEAN_MEMO_PROBE_LIMIT)));
19194        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Sparse);
19195
19196        let mut promote = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
19197        let repeated = key(1);
19198        for _ in 0..=CLEAN_MEMO_REPEAT_LIMIT {
19199            assert!(promote.clean_memo_enabled_for_key(&repeated));
19200        }
19201        assert_eq!(promote.clean_memo_mode, CleanMemoMode::Promote);
19202
19203        for _ in 1..CLEAN_MEMO_REPROBE_INTERVAL {
19204            assert!(!sparse.clean_memo_enabled_for_key(&repeated));
19205        }
19206        assert!(sparse.clean_memo_enabled_for_key(&repeated));
19207        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Probe);
19208        for _ in 0..CLEAN_MEMO_REPEAT_LIMIT {
19209            assert!(sparse.clean_memo_enabled_for_key(&repeated));
19210        }
19211        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Promote);
19212    }
19213
19214    #[test]
19215    fn fast_recognize_memo_capacity_scales_from_small_floor_to_bounded_maximum() {
19216        assert_eq!(
19217            fast_recognize_memo_capacity(0),
19218            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
19219        );
19220        assert_eq!(
19221            fast_recognize_memo_capacity(FAST_RECOGNIZE_MIN_MEMO_CAPACITY / 8),
19222            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
19223        );
19224        assert_eq!(fast_recognize_memo_capacity(1_000), 8_000);
19225        assert_eq!(
19226            fast_recognize_memo_capacity(usize::MAX),
19227            FAST_RECOGNIZE_MAX_MEMO_CAPACITY
19228        );
19229    }
19230
19231    #[test]
19232    fn fast_recognize_scratch_reuses_small_tables_and_releases_oversized_memo() {
19233        let mut scratch = FastRecognizeTopScratch::default();
19234        scratch.prepare(FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
19235        let retained_capacity = scratch.memo.capacity();
19236        assert!(retained_capacity >= FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
19237        assert!(retained_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19238
19239        let larger_capacity = retained_capacity + 1;
19240        scratch.prepare(larger_capacity);
19241        let grown_capacity = scratch.memo.capacity();
19242        assert!(grown_capacity >= larger_capacity);
19243        assert!(grown_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19244
19245        scratch.memo.insert(
19246            FastRecognizeKey {
19247                state_number: 0,
19248                stop_state: 0,
19249                index: 0,
19250                rule_start_index: 0,
19251                decision_start_index: None,
19252                precedence: 0,
19253                recovery_symbols_id: 0,
19254                recovery_state: None,
19255            },
19256            Rc::from([FastRecognizeOutcome {
19257                index: 0,
19258                consumed_eof: false,
19259                diagnostics: DiagnosticSeqId::EMPTY,
19260                deferred_nodes: FastDeferredNodeId::EMPTY,
19261                nodes: NodeSeqId::EMPTY,
19262            }]),
19263        );
19264        scratch.release_oversized_memo();
19265        assert!(scratch.memo.is_empty());
19266        assert_eq!(scratch.memo.capacity(), grown_capacity);
19267
19268        scratch
19269            .memo
19270            .reserve(FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY * 2);
19271        assert!(scratch.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19272
19273        scratch.release_oversized_memo();
19274        assert!(scratch.memo.is_empty());
19275        assert_eq!(scratch.memo.capacity(), 0);
19276    }
19277
19278    #[test]
19279    fn clean_empty_multi_alt_outcomes_are_memoized() {
19280        let mut atn = ParserAtnBuilder::new(2);
19281        assert_eq!(
19282            atn.add_state(AtnStateKind::RuleStart, Some(0))
19283                .expect("state")
19284                .index(),
19285            0
19286        );
19287        assert_eq!(
19288            atn.add_state(AtnStateKind::BlockStart, Some(0))
19289                .expect("state")
19290                .index(),
19291            1
19292        );
19293        assert_eq!(
19294            atn.add_state(AtnStateKind::RuleStop, Some(0))
19295                .expect("state")
19296                .index(),
19297            2
19298        );
19299        atn.set_rule_to_start_state(vec![0])
19300            .expect("rule start states");
19301        atn.set_rule_to_stop_state(vec![2])
19302            .expect("rule stop states");
19303        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
19304            .expect("transition");
19305        atn.add_transition(
19306            1,
19307            ParserTransitionSpec::Atom {
19308                target: 2,
19309                label: 1,
19310            },
19311        )
19312        .expect("transition");
19313        atn.add_transition(
19314            1,
19315            ParserTransitionSpec::Atom {
19316                target: 2,
19317                label: 2,
19318            },
19319        )
19320        .expect("transition");
19321        let atn = finish_atn(atn);
19322
19323        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
19324        parser.fast_recovery_enabled = false;
19325        let mut visiting = FxHashSet::default();
19326        let mut memo = FxHashMap::default();
19327        let mut expected = ExpectedTokens::default();
19328        let outcomes = parser.recognize_state_fast(
19329            &atn,
19330            FastRecognizeRequest {
19331                state_number: 1,
19332                stop_state: 2,
19333                index: 0,
19334                rule_start_index: 0,
19335                decision_start_index: None,
19336                precedence: 0,
19337                depth: 0,
19338                recovery_symbols: parser.empty_recovery_symbols(),
19339                recovery_state: None,
19340            },
19341            FastRecognizeScratch {
19342                predicate_context: None,
19343                visiting: &mut visiting,
19344                memo: &mut memo,
19345                expected: &mut expected,
19346                native_depth: 0,
19347            },
19348        );
19349
19350        assert!(outcomes.is_empty());
19351        assert_eq!(memo.len(), 1);
19352        assert!(memo.values().next().expect("memo entry").is_empty());
19353
19354        parser.clean_memo_mode = CleanMemoMode::Sparse;
19355        visiting.clear();
19356        memo.clear();
19357        expected = ExpectedTokens::default();
19358        let sparse_outcomes = parser.recognize_state_fast(
19359            &atn,
19360            FastRecognizeRequest {
19361                state_number: 1,
19362                stop_state: 2,
19363                index: 0,
19364                rule_start_index: 0,
19365                decision_start_index: None,
19366                precedence: 0,
19367                depth: 0,
19368                recovery_symbols: parser.empty_recovery_symbols(),
19369                recovery_state: None,
19370            },
19371            FastRecognizeScratch {
19372                predicate_context: None,
19373                visiting: &mut visiting,
19374                memo: &mut memo,
19375                expected: &mut expected,
19376                native_depth: 0,
19377            },
19378        );
19379
19380        assert!(sparse_outcomes.is_empty());
19381        assert!(memo.is_empty());
19382    }
19383
19384    #[test]
19385    fn wildcard_matches_non_eof_only() {
19386        let mut parser = mini_parser(vec![
19387            TestToken::new(1).with_text("x"),
19388            TestToken::eof("parser-test", 1, 1, 1),
19389        ]);
19390        let matched = parser.match_wildcard().expect("wildcard");
19391        assert_eq!(parser.node(matched).text(), "x");
19392        assert!(parser.match_wildcard().is_err());
19393    }
19394
19395    #[test]
19396    fn add_parse_child_records_match_even_without_tree_building() {
19397        // `sync_decision`'s "is the current context empty" flag must reflect real
19398        // matches, not parse-tree children: when `build_parse_trees(false)`,
19399        // `children` stays empty but `has_matched_child` must still flip so nested
19400        // recovery does not wrongly suppress single-token deletion.
19401        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
19402        let token = TestToken::new(1).with_text("x");
19403
19404        parser.set_build_parse_trees(false);
19405        let mut ctx = ParserRuleContext::new(0, 0);
19406        assert!(!ctx.has_matched_child());
19407        let child = parser.terminal_tree(token.id);
19408        parser.add_parse_child(&mut ctx, child);
19409        // Tree building is off, so no child is stored...
19410        assert_eq!(ctx.child_count(), 0);
19411        assert_eq!(parser.parse_tree_storage().node_count(), 0);
19412        // ...but the match is recorded, so the context is no longer "empty".
19413        assert!(ctx.has_matched_child());
19414
19415        // With tree building on, the child is stored and the match is recorded.
19416        parser.set_build_parse_trees(true);
19417        let mut ctx = ParserRuleContext::new(0, 0);
19418        let child = parser.terminal_tree(token.id);
19419        parser.add_parse_child(&mut ctx, child);
19420        assert_eq!(ctx.child_count(), 1);
19421        assert!(ctx.has_matched_child());
19422    }
19423
19424    #[test]
19425    fn disabled_tree_building_does_not_grow_flat_storage() {
19426        let mut parser = mini_parser(vec![
19427            TestToken::new(1).with_text("x"),
19428            TestToken::new(1).with_text("y"),
19429            TestToken::eof("parser-test", 2, 1, 2),
19430        ]);
19431        parser.set_build_parse_trees(false);
19432        let mut context = ParserRuleContext::new(0, -1);
19433
19434        for _ in 0..2 {
19435            let child = parser.match_token(1).expect("token should match");
19436            parser.add_parse_child(&mut context, child);
19437        }
19438        let current = parser.input.lt_id(1).expect("EOF token");
19439        let error = parser.error_tree(current);
19440        parser.add_parse_child(&mut context, error);
19441        let root = parser.rule_node(context);
19442
19443        assert_eq!(
19444            parser.parse_tree_storage().stats(),
19445            ParseTreeStats::default()
19446        );
19447        assert!(
19448            parser
19449                .parse_tree_storage()
19450                .node(parser.token_store(), root)
19451                .is_none(),
19452            "the no-tree sentinel must not resolve to stored data"
19453        );
19454    }
19455
19456    #[test]
19457    fn disabled_tree_building_skips_recognition_rule_node_storage() {
19458        let atn = ordinary_star_loop_atn();
19459        let mut parser = mini_parser(repeated_x_tokens(3));
19460        parser.set_build_parse_trees(false);
19461
19462        parser
19463            .parse_atn_rule(&atn, 0)
19464            .expect("ordinary repetition should parse without a tree");
19465
19466        assert_eq!(parser.input.index(), 3);
19467        assert!(parser.recognition_arena.nodes.is_empty());
19468        assert!(parser.recognition_arena.seq_links.is_empty());
19469        assert!(parser.recognition_arena.deferred_nodes.is_empty());
19470        assert!(parser.recognition_arena.deferred_rules.is_empty());
19471        assert!(!parser.fast_token_nodes_enabled);
19472        assert!(parser.fast_recognize_scratch.memo.is_empty());
19473    }
19474
19475    #[test]
19476    fn parser_interprets_simple_atn_rule() {
19477        let atn = token_then_eof_atn();
19478        let mut parser = mini_parser(vec![
19479            TestToken::new(1).with_text("x"),
19480            TestToken::eof("parser-test", 1, 1, 1),
19481        ]);
19482
19483        let tree = parser
19484            .parse_atn_rule(&atn, 0)
19485            .expect("artificial parser rule should parse");
19486        assert_eq!(parser.node(tree).text(), "x<EOF>");
19487        assert_eq!(parser.number_of_syntax_errors(), 0);
19488        assert_eq!(
19489            parser
19490                .node(tree)
19491                .first_rule_stop(0)
19492                .expect("rule should stop at EOF")
19493                .token_type(),
19494            TOKEN_EOF
19495        );
19496
19497        let mut parser = mini_parser(vec![
19498            TestToken::new(1).with_text("x"),
19499            TestToken::eof("parser-test", 1, 1, 1),
19500        ]);
19501        let (tree, actions) = parser
19502            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19503            .expect("runtime-option parser rule should parse");
19504        assert!(actions.is_empty());
19505        assert_eq!(
19506            parser
19507                .node(tree)
19508                .first_rule_stop(0)
19509                .expect("rule should stop at EOF")
19510                .token_type(),
19511            TOKEN_EOF
19512        );
19513    }
19514
19515    #[test]
19516    fn runtime_options_default_ignores_noop_action_transitions() {
19517        let atn = noop_action_then_token_then_eof_atn();
19518        let mut parser = mini_parser(vec![
19519            TestToken::new(1).with_text("x"),
19520            TestToken::eof("parser-test", 1, 1, 1),
19521        ]);
19522
19523        let (tree, actions) = parser
19524            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19525            .expect("no-op parser action should not force action replay");
19526
19527        assert_eq!(parser.node(tree).text(), "x<EOF>");
19528        assert!(
19529            actions.is_empty(),
19530            "action_index=None transitions are ANTLR metadata, not replay actions"
19531        );
19532        assert_eq!(parser.number_of_syntax_errors(), 0);
19533    }
19534
19535    #[test]
19536    fn parser_exposes_buffered_token_stream_after_parse() {
19537        let atn = token_then_eof_atn();
19538        let mut parser = mini_parser(vec![
19539            TestToken::new(1).with_text("x"),
19540            TestToken::eof("parser-test", 1, 1, 1),
19541        ]);
19542
19543        let tree = parser
19544            .parse_atn_rule(&atn, 0)
19545            .expect("artificial parser rule should parse");
19546        assert_eq!(parser.node(tree).text(), "x<EOF>");
19547
19548        let stream = parser.token_stream();
19549        let source_index_after_parse = stream.token_source().index;
19550        let buffered = stream.tokens().collect::<Vec<_>>();
19551        assert_eq!(buffered.len(), 2);
19552        assert_eq!(buffered[0].text(), Some("x"));
19553        assert_eq!(buffered[0].token_id().index(), 0);
19554        assert_eq!(buffered[1].token_type(), TOKEN_EOF);
19555        assert_eq!(stream.token_source().index, source_index_after_parse);
19556        drop(buffered);
19557
19558        let stream = parser.into_token_stream();
19559        assert_eq!(stream.token_source().index, source_index_after_parse);
19560        assert_eq!(
19561            stream.tokens().next().expect("first token").text(),
19562            Some("x")
19563        );
19564        assert_eq!(
19565            stream.tokens().nth(1).expect("EOF token").token_type(),
19566            TOKEN_EOF
19567        );
19568    }
19569
19570    #[test]
19571    fn parsed_file_exposes_all_buffered_tokens() {
19572        let atn = token_then_eof_atn();
19573        let mut parser = mini_parser(vec![
19574            TestToken::new(99)
19575                .with_text(" comment")
19576                .with_channel(HIDDEN_CHANNEL),
19577            TestToken::new(1).with_text("x"),
19578            TestToken::eof("parser-test", 9, 1, 9),
19579        ]);
19580
19581        let tree = parser
19582            .parse_atn_rule(&atn, 0)
19583            .expect("artificial parser rule should parse");
19584        let parsed = parser.into_parsed_file(tree);
19585
19586        // Snapshot the full buffered stream — hidden-channel comment, default-channel token, EOF —
19587        // as (type, channel, text) triples; contents make the count self-evident.
19588        insta::assert_debug_snapshot!(
19589            "parsed_file_exposes_all_buffered_tokens",
19590            parsed
19591                .tokens()
19592                .iter()
19593                .map(|token| (token.token_type(), token.channel(), token.text()))
19594                .collect::<Vec<_>>()
19595        );
19596        assert_eq!(parsed.tokens().into_iter().count(), 3);
19597    }
19598
19599    #[test]
19600    fn parser_syntax_error_count_tracks_interpreted_recovery() {
19601        let atn = token_then_eof_atn();
19602        let mut parser = mini_parser(vec![
19603            TestToken::new(1).with_text("x"),
19604            TestToken::new(2).with_text("y"),
19605            TestToken::eof("parser-test", 2, 1, 2),
19606        ]);
19607
19608        let tree = parser
19609            .parse_atn_rule(&atn, 0)
19610            .expect("invalid token should recover into an error node");
19611
19612        assert_eq!(parser.number_of_syntax_errors(), 1);
19613        assert_eq!(
19614            parser
19615                .node(tree)
19616                .first_error_token()
19617                .expect("recovery should embed an error token")
19618                .text(),
19619            Some("y")
19620        );
19621    }
19622
19623    #[test]
19624    fn failed_interpreted_parse_notifies_error_listener() {
19625        let atn = token_then_eof_atn();
19626        let mut parser = mini_parser(vec![
19627            TestToken::new(2)
19628                .with_text("y")
19629                .with_span(0, 0)
19630                .with_byte_span(0, 1)
19631                .with_position(3, 5),
19632            TestToken::eof("parser-test", 1, 1, 1),
19633        ]);
19634        parser.remove_error_listeners();
19635        let diagnostics = Arc::new(Mutex::new(Vec::new()));
19636        parser.add_error_listener(RecordingErrorListener {
19637            diagnostics: Arc::clone(&diagnostics),
19638        });
19639
19640        let error = parser
19641            .parse_atn_rule(&atn, 0)
19642            .expect_err("start-rule mismatch should remain a parser error");
19643
19644        assert_eq!(parser.number_of_syntax_errors(), 1);
19645        assert!(matches!(&error, AntlrError::ParserError { .. }));
19646        insta::assert_debug_snapshot!(
19647            "failed_interpreted_parse_notifies_error_listener",
19648            *diagnostics.lock().expect("recorded diagnostics lock")
19649        );
19650    }
19651
19652    #[test]
19653    fn adaptive_direct_rule_uses_simulator_decision() {
19654        let atn = two_alt_decision_atn();
19655        let mut simulator = ParserAtnSimulator::new(&atn);
19656        let mut parser = mini_parser(vec![
19657            TestToken::new(2).with_text("y"),
19658            TestToken::eof("parser-test", 1, 1, 1),
19659        ]);
19660
19661        let tree = parser
19662            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19663            .expect("direct adaptive rule should parse");
19664
19665        assert_eq!(parser.node(tree).text(), "y");
19666        assert_eq!(parser.input.index(), 1);
19667    }
19668
19669    #[test]
19670    fn adaptive_direct_rule_restores_input_on_fallback() {
19671        let atn = predicate_after_token_atn();
19672        let mut simulator = ParserAtnSimulator::new(&atn);
19673        let mut parser = mini_parser(vec![
19674            TestToken::new(1).with_text("x"),
19675            TestToken::new(2).with_text("y"),
19676            TestToken::eof("parser-test", 2, 1, 2),
19677        ]);
19678
19679        let tree = parser
19680            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19681            .expect("fallback recognizer should parse");
19682
19683        assert_eq!(parser.node(tree).text(), "xy");
19684        assert_eq!(parser.input.index(), 2);
19685        let stats = parser.parse_tree_storage().stats();
19686        assert_eq!(stats.nodes, parser.node(tree).descendants().count());
19687        assert_eq!(stats.edges, stats.nodes.saturating_sub(1));
19688        assert_eq!(stats.scratch_links, 0);
19689    }
19690
19691    #[test]
19692    fn unknown_predicate_policy_defaults_to_assume_true() {
19693        let atn = predicate_after_token_atn();
19694        let mut parser = mini_parser(vec![
19695            TestToken::new(1).with_text("x"),
19696            TestToken::new(2).with_text("y"),
19697            TestToken::eof("parser-test", 2, 1, 2),
19698        ]);
19699
19700        let (tree, _) = parser
19701            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19702            .expect("unknown predicate should pass under the default policy");
19703
19704        assert_eq!(parser.node(tree).text(), "xy");
19705        assert_eq!(parser.number_of_syntax_errors(), 0);
19706    }
19707
19708    #[test]
19709    fn private_context_alt_tracking_keeps_fast_predicate_recognition() {
19710        let atn = predicate_gated_same_lookahead_atn([0, 1]);
19711        let mut parser = mini_parser(vec![
19712            TestToken::new(1).with_text("x"),
19713            TestToken::eof("parser-test", 1, 1, 1),
19714        ]);
19715
19716        let (tree, _) = parser
19717            .parse_atn_rule_with_runtime_options(
19718                &atn,
19719                0,
19720                ParserRuntimeOptions {
19721                    predicates: &[
19722                        (0, 0, ParserPredicate::False),
19723                        (0, 1, ParserPredicate::True),
19724                    ],
19725                    track_context_alt_numbers: true,
19726                    ..ParserRuntimeOptions::default()
19727                },
19728            )
19729            .expect("the second predicate-gated alternative should match");
19730
19731        let root = parser.node(tree).as_rule().expect("entry result is a rule");
19732        insta::assert_debug_snapshot!(
19733            "private_context_alt_tracking_keeps_fast_predicate_recognition",
19734            (root.alt_number(), root.context_alt_number(), root.text())
19735        );
19736        assert_eq!(parser.number_of_syntax_errors(), 0);
19737        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&false));
19738        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 1)), Some(&true));
19739    }
19740
19741    #[test]
19742    fn nested_interpreted_parse_preserves_prior_unknown_predicate_hits() {
19743        // A generated parent may record an unknown-predicate coordinate, then
19744        // descend into an interpreted child. The child's interpreter entry must
19745        // not wipe the parent's recorded hit before the top-level surfaces it.
19746        let atn = token_then_eof_atn();
19747        let mut parser = mini_parser(vec![
19748            TestToken::new(1).with_text("x"),
19749            TestToken::eof("parser-test", 1, 1, 1),
19750        ]);
19751
19752        // Simulate the parent having recorded a fail-loud coordinate.
19753        parser.unknown_predicate_hits.push((7, 3));
19754
19755        // Run an interpreted child parse that records no coordinate of its own.
19756        parser
19757            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19758            .expect("child rule parses");
19759
19760        // The parent's coordinate must still be present for the top-level entry.
19761        let error = parser
19762            .take_unknown_semantic_error()
19763            .expect("parent's recorded coordinate must survive the nested interpreted parse");
19764        let AntlrError::Unsupported(message) = error else {
19765            panic!("expected AntlrError::Unsupported, got {error:?}");
19766        };
19767        assert!(message.contains("pred_index=3"), "message: {message}");
19768    }
19769
19770    #[test]
19771    fn nested_committed_parse_preserves_prior_unhandled_action_hits() {
19772        let atn = token_then_eof_atn();
19773        let mut parser = mini_parser(vec![
19774            TestToken::new(1).with_text("x"),
19775            TestToken::eof("parser-test", 1, 1, 1),
19776        ]);
19777        parser.unhandled_action_hits.push((7, 42));
19778
19779        parser
19780            .parse_atn_rule_with_runtime_options(
19781                &atn,
19782                0,
19783                ParserRuntimeOptions {
19784                    action_indices: &[(usize::MAX, 0)],
19785                    ..ParserRuntimeOptions::default()
19786                },
19787            )
19788            .expect("a child with no action miss must not observe its parent's miss");
19789
19790        let error = parser
19791            .take_unknown_semantic_error()
19792            .expect("the parent's action miss must survive the nested committed parse");
19793        let AntlrError::Unsupported(message) = error else {
19794            panic!("expected AntlrError::Unsupported, got {error:?}");
19795        };
19796        assert!(
19797            message.contains("rule_index=7") && message.contains("state=42"),
19798            "message: {message}"
19799        );
19800    }
19801
19802    #[test]
19803    fn unknown_predicate_policy_assume_false_kills_the_guarded_path() {
19804        let atn = predicate_after_token_atn();
19805        let mut parser = mini_parser(vec![
19806            TestToken::new(1).with_text("x"),
19807            TestToken::new(2).with_text("y"),
19808            TestToken::eof("parser-test", 2, 1, 2),
19809        ]);
19810
19811        let result = parser.parse_atn_rule_with_runtime_options(
19812            &atn,
19813            0,
19814            ParserRuntimeOptions {
19815                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
19816                ..ParserRuntimeOptions::default()
19817            },
19818        );
19819
19820        assert!(
19821            result.is_err(),
19822            "the only path is predicate-guarded, so assume-false must fail the parse"
19823        );
19824    }
19825
19826    #[test]
19827    fn predicate_failure_message_keeps_semantic_recovery_path() {
19828        let atn = predicate_after_token_atn();
19829        let mut parser = mini_parser(vec![
19830            TestToken::new(1).with_text("x"),
19831            TestToken::new(2).with_text("y"),
19832            TestToken::eof("parser-test", 2, 1, 2),
19833        ]);
19834
19835        let (tree, _) = parser
19836            .parse_atn_rule_with_runtime_options(
19837                &atn,
19838                0,
19839                ParserRuntimeOptions {
19840                    predicates: &[(
19841                        0,
19842                        0,
19843                        ParserPredicate::FalseWithMessage {
19844                            message: "predicate rejected input",
19845                        },
19846                    )],
19847                    ..ParserRuntimeOptions::default()
19848                },
19849            )
19850            .expect("failure-message predicates recover through the semantic interpreter");
19851
19852        assert_eq!(parser.node(tree).text(), "xy");
19853        assert_eq!(parser.number_of_syntax_errors(), 1);
19854        assert!(
19855            parser.fast_predicate_cache.is_empty(),
19856            "failure-message predicates need the semantic interpreter's recovery outcome"
19857        );
19858    }
19859
19860    #[test]
19861    fn unknown_predicate_policy_error_names_the_coordinate() {
19862        let atn = predicate_after_token_atn();
19863        let mut parser = mini_parser(vec![
19864            TestToken::new(1).with_text("x"),
19865            TestToken::new(2).with_text("y"),
19866            TestToken::eof("parser-test", 2, 1, 2),
19867        ]);
19868
19869        let error = parser
19870            .parse_atn_rule_with_runtime_options(
19871                &atn,
19872                0,
19873                ParserRuntimeOptions {
19874                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19875                    ..ParserRuntimeOptions::default()
19876                },
19877            )
19878            .expect_err("evaluating an unknown predicate under Error policy must fail");
19879
19880        let AntlrError::Unsupported(message) = error else {
19881            panic!("expected AntlrError::Unsupported, got {error:?}");
19882        };
19883        assert!(
19884            message.contains("unsupported semantic predicate"),
19885            "message should name the failure class: {message}"
19886        );
19887        assert!(
19888            message.contains("pred_index=0"),
19889            "message should carry the coordinate: {message}"
19890        );
19891    }
19892
19893    #[test]
19894    fn fail_loud_hits_do_not_leak_into_a_reused_interpreter_parse() {
19895        // A parser reused after a fail-loud parse must not carry the old
19896        // coordinates into a later parse. The fail-loud return keeps the hits
19897        // (so a generated parent can surface a recovered child's coordinate),
19898        // and the next parse's entry stashes/replaces them, so a subsequent
19899        // clean parse surfaces no stale error.
19900        let atn = predicate_after_token_atn();
19901        let mut parser = mini_parser(vec![
19902            TestToken::new(1).with_text("x"),
19903            TestToken::new(2).with_text("y"),
19904            TestToken::eof("parser-test", 2, 1, 2),
19905        ]);
19906
19907        parser
19908            .parse_atn_rule_with_runtime_options(
19909                &atn,
19910                0,
19911                ParserRuntimeOptions {
19912                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19913                    ..ParserRuntimeOptions::default()
19914                },
19915            )
19916            .expect_err("first parse fails loud under the Error policy");
19917
19918        // The failed parse kept its coordinate on the parser (so a generated
19919        // parent could surface a recovered child). A top-level reuse resets the
19920        // hits — generated parsers call `reset_unknown_semantic_hits` at their
19921        // public entry; direct interpreter-API callers do the same.
19922        parser.reset_unknown_semantic_hits();
19923        assert!(
19924            parser.take_unknown_semantic_error().is_none(),
19925            "reset must drop stale unknown-predicate coordinates before a reused parse"
19926        );
19927    }
19928
19929    #[derive(Debug, Default)]
19930    struct RecordingHooks {
19931        predicates: Vec<(usize, usize, usize, Option<String>)>,
19932        actions: Vec<(usize, String, Option<String>)>,
19933        action_trees: Vec<Option<String>>,
19934    }
19935
19936    impl SemanticHooks for RecordingHooks {
19937        fn sempred<S>(
19938            &mut self,
19939            ctx: &mut ParserSemCtx<'_, S>,
19940            rule_index: usize,
19941            pred_index: usize,
19942        ) -> Option<bool>
19943        where
19944            S: TokenSource,
19945        {
19946            self.predicates.push((
19947                ctx.input_index(),
19948                rule_index,
19949                pred_index,
19950                ctx.token_text(1)
19951                    .and_then(|token| token.text().map(str::to_owned)),
19952            ));
19953            Some(true)
19954        }
19955
19956        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19957        where
19958            S: TokenSource,
19959        {
19960            self.actions.push((
19961                action.source_state(),
19962                ctx.action_text(),
19963                ctx.rule_name().map(str::to_owned),
19964            ));
19965            self.action_trees.push(ctx.tree().map(Node::text));
19966            true
19967        }
19968    }
19969
19970    #[derive(Debug, Default)]
19971    struct StatefulActionHooks {
19972        entered: bool,
19973        events: Vec<String>,
19974    }
19975
19976    impl SemanticHooks for StatefulActionHooks {
19977        fn sempred<S>(
19978            &mut self,
19979            _ctx: &mut ParserSemCtx<'_, S>,
19980            _rule_index: usize,
19981            _pred_index: usize,
19982        ) -> Option<bool>
19983        where
19984            S: TokenSource,
19985        {
19986            self.events.push(format!("predicate:{}", self.entered));
19987            Some(self.entered)
19988        }
19989
19990        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19991        where
19992            S: TokenSource,
19993        {
19994            self.events.push(format!(
19995                "action:{}",
19996                action
19997                    .action_index()
19998                    .map_or_else(|| "legacy".to_owned(), |index| index.to_string())
19999            ));
20000            self.entered = true;
20001            true
20002        }
20003    }
20004
20005    #[derive(Debug, Default)]
20006    struct InitOrderingHooks {
20007        initialized: bool,
20008        events: Vec<String>,
20009    }
20010
20011    impl SemanticHooks for InitOrderingHooks {
20012        fn sempred<S>(
20013            &mut self,
20014            _ctx: &mut ParserSemCtx<'_, S>,
20015            _rule_index: usize,
20016            _pred_index: usize,
20017        ) -> Option<bool>
20018        where
20019            S: TokenSource,
20020        {
20021            self.events.push(format!("predicate:{}", self.initialized));
20022            Some(self.initialized)
20023        }
20024
20025        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
20026        where
20027            S: TokenSource,
20028        {
20029            if action.is_rule_init() {
20030                self.initialized = true;
20031                self.events.push("init".to_owned());
20032            } else {
20033                self.events.push(format!(
20034                    "action:{}:initialized={}",
20035                    action
20036                        .action_index()
20037                        .map_or_else(|| "legacy".to_owned(), |index| index.to_string()),
20038                    self.initialized
20039                ));
20040            }
20041            true
20042        }
20043    }
20044
20045    #[derive(Debug, Default)]
20046    struct ActionContextHooks {
20047        actions: Vec<(usize, Option<i64>, Option<usize>)>,
20048    }
20049
20050    impl SemanticHooks for ActionContextHooks {
20051        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
20052        where
20053            S: TokenSource,
20054        {
20055            self.actions.push((
20056                action.action_index().unwrap_or(usize::MAX),
20057                ctx.local_int_arg(),
20058                action.stop_index(),
20059            ));
20060            true
20061        }
20062    }
20063
20064    #[derive(Debug, Default)]
20065    struct DecliningActionHooks {
20066        actions: Vec<usize>,
20067    }
20068
20069    impl SemanticHooks for DecliningActionHooks {
20070        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
20071        where
20072            S: TokenSource,
20073        {
20074            self.actions.push(action.source_state());
20075            false
20076        }
20077    }
20078
20079    #[derive(Debug, Default)]
20080    struct ForcedSecondAlternativeHooks {
20081        decisions: Vec<(usize, usize, usize)>,
20082    }
20083
20084    impl SemanticHooks for ForcedSecondAlternativeHooks {
20085        fn observes_parser_decisions(&self) -> bool {
20086            true
20087        }
20088
20089        fn parser_decision_override(
20090            &mut self,
20091            decision: usize,
20092            input_index: usize,
20093            alternative_count: usize,
20094        ) -> Option<usize> {
20095            self.decisions
20096                .push((decision, input_index, alternative_count));
20097            Some(2)
20098        }
20099    }
20100
20101    #[derive(Debug, Default)]
20102    struct ContainmentRecoveryHooks {
20103        decisions: Vec<(usize, usize, usize)>,
20104    }
20105
20106    impl SemanticHooks for ContainmentRecoveryHooks {
20107        fn observes_parser_decisions(&self) -> bool {
20108            true
20109        }
20110
20111        fn parser_decision_override(
20112            &mut self,
20113            decision: usize,
20114            input_index: usize,
20115            alternative_count: usize,
20116        ) -> Option<usize> {
20117            self.decisions
20118                .push((decision, input_index, alternative_count));
20119            (decision == 1).then_some(1)
20120        }
20121    }
20122
20123    struct RecordingParseListener {
20124        events: Arc<Mutex<Vec<String>>>,
20125    }
20126
20127    impl ParseListener for RecordingParseListener {
20128        fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError> {
20129            self.events
20130                .lock()
20131                .expect("parse-listener event lock")
20132                .push(format!("enter:{}", event.rule_index));
20133            Ok(())
20134        }
20135
20136        fn exit_every_rule(&mut self, rule_index: usize) {
20137            self.events
20138                .lock()
20139                .expect("parse-listener event lock")
20140                .push(format!("exit:{rule_index}"));
20141        }
20142    }
20143
20144    #[derive(Debug, Default)]
20145    struct RejectingPredicateHooks {
20146        predicates: Vec<(usize, usize, usize, Option<String>)>,
20147    }
20148
20149    impl SemanticHooks for RejectingPredicateHooks {
20150        fn sempred<S>(
20151            &mut self,
20152            ctx: &mut ParserSemCtx<'_, S>,
20153            rule_index: usize,
20154            pred_index: usize,
20155        ) -> Option<bool>
20156        where
20157            S: TokenSource,
20158        {
20159            self.predicates.push((
20160                ctx.input_index(),
20161                rule_index,
20162                pred_index,
20163                ctx.token_text(1)
20164                    .and_then(|token| token.text().map(str::to_owned)),
20165            ));
20166            Some(false)
20167        }
20168    }
20169
20170    #[test]
20171    fn fast_predicate_cache_replays_hook_once_per_coordinate_and_input() {
20172        let atn = predicate_gated_same_lookahead_atn([0, 0]);
20173        let mut parser = mini_parser_with_hooks(
20174            vec![
20175                TestToken::new(1).with_text("x"),
20176                TestToken::eof("parser-test", 1, 1, 1),
20177            ],
20178            RecordingHooks::default(),
20179        );
20180
20181        let (tree, _) = parser
20182            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
20183            .expect("both alternatives share one replay-safe predicate result");
20184
20185        assert_eq!(parser.node(tree).text(), "x<EOF>");
20186        assert_eq!(
20187            parser.semantic_hooks.predicates,
20188            vec![(0, 0, 0, Some("x".to_owned()))]
20189        );
20190        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&true));
20191    }
20192
20193    #[test]
20194    fn semantic_hook_handles_unknown_predicate_before_error_policy() {
20195        let atn = predicate_after_token_atn();
20196        let mut parser = mini_parser_with_hooks(
20197            vec![
20198                TestToken::new(1).with_text("x"),
20199                TestToken::new(2).with_text("y"),
20200                TestToken::eof("parser-test", 2, 1, 2),
20201            ],
20202            RecordingHooks::default(),
20203        );
20204
20205        let (tree, _) = parser
20206            .parse_atn_rule_with_runtime_options(
20207                &atn,
20208                0,
20209                ParserRuntimeOptions {
20210                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20211                    ..ParserRuntimeOptions::default()
20212                },
20213            )
20214            .expect("hook supplies the missing predicate result");
20215
20216        assert_eq!(parser.node(tree).text(), "xy");
20217        assert_eq!(
20218            parser.semantic_hooks.predicates,
20219            vec![(1, 0, 0, Some("y".to_owned()))]
20220        );
20221        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&true));
20222    }
20223
20224    #[test]
20225    fn runtime_options_default_preserves_semantic_hook_predicates() {
20226        let atn = predicate_after_token_atn();
20227        let mut parser = mini_parser_with_hooks(
20228            vec![
20229                TestToken::new(1).with_text("x"),
20230                TestToken::new(2).with_text("y"),
20231                TestToken::eof("parser-test", 2, 1, 2),
20232            ],
20233            RejectingPredicateHooks::default(),
20234        );
20235
20236        let result =
20237            parser.parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default());
20238
20239        assert!(
20240            result.is_err(),
20241            "default runtime options must not bypass semantic hooks for predicate ATNs"
20242        );
20243        assert_eq!(
20244            parser.semantic_hooks.predicates,
20245            vec![(1, 0, 0, Some("y".to_owned()))]
20246        );
20247        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&false));
20248    }
20249
20250    #[test]
20251    fn committed_action_runs_before_later_predicate() {
20252        let atn = committed_action_then_predicate_atn();
20253        let mut parser = mini_parser_with_hooks(
20254            vec![
20255                TestToken::new(1).with_text("x"),
20256                TestToken::eof("parser-test", 1, 1, 1),
20257            ],
20258            StatefulActionHooks::default(),
20259        );
20260
20261        let (tree, deferred_actions) = parser
20262            .parse_atn_rule_with_runtime_options(
20263                &atn,
20264                0,
20265                ParserRuntimeOptions {
20266                    action_indices: &[(0, 7)],
20267                    ..ParserRuntimeOptions::default()
20268                },
20269            )
20270            .expect("the predicate should observe the preceding committed action");
20271
20272        assert_eq!(parser.node(tree).text(), "x<EOF>");
20273        assert!(deferred_actions.is_empty());
20274        assert_eq!(parser.semantic_hooks.events, ["action:7", "predicate:true"]);
20275    }
20276
20277    #[test]
20278    fn committed_action_hook_observes_parameterized_rule_argument() {
20279        let atn = parameterized_child_action_eof_atn();
20280        let rule_args = [ParserRuleArg {
20281            source_state: 0,
20282            rule_index: 1,
20283            value: 42,
20284            inherit_local: false,
20285        }];
20286        let mut parser = mini_parser_with_hooks(
20287            vec![TestToken::eof("parser-test", 0, 1, 0)],
20288            ActionContextHooks::default(),
20289        );
20290
20291        parser
20292            .parse_atn_rule_with_runtime_options(
20293                &atn,
20294                0,
20295                ParserRuntimeOptions {
20296                    action_indices: &[(1, 20), (4, 10)],
20297                    rule_args: &rule_args,
20298                    ..ParserRuntimeOptions::default()
20299                },
20300            )
20301            .expect("the parameterized child should parse");
20302
20303        assert_eq!(
20304            parser.semantic_hooks.actions[0],
20305            (10, Some(42), None),
20306            "the child action should observe its invocation argument"
20307        );
20308    }
20309
20310    #[test]
20311    fn committed_parent_propagates_child_eof_consumption() {
20312        let atn = parameterized_child_action_eof_atn();
20313        let mut parser = mini_parser_with_hooks(
20314            vec![TestToken::eof("parser-test", 0, 1, 0)],
20315            ActionContextHooks::default(),
20316        );
20317
20318        let (tree, _) = parser
20319            .parse_atn_rule_with_runtime_options(
20320                &atn,
20321                0,
20322                ParserRuntimeOptions {
20323                    action_indices: &[(1, 20), (4, 10)],
20324                    ..ParserRuntimeOptions::default()
20325                },
20326            )
20327            .expect("the parent should retain its child's EOF boundary");
20328
20329        assert_eq!(
20330            parser.semantic_hooks.actions[1],
20331            (20, None, Some(0)),
20332            "the parent action should stop at EOF"
20333        );
20334        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20335        assert_eq!(root.stop().map(|token| token.token_type()), Some(TOKEN_EOF));
20336        let child = root
20337            .child_rules(1)
20338            .next()
20339            .expect("the parent should contain the child rule");
20340        assert_eq!(
20341            child.stop().map(|token| token.token_type()),
20342            Some(TOKEN_EOF)
20343        );
20344    }
20345
20346    #[test]
20347    fn committed_walker_does_not_run_action_in_losing_alternative() {
20348        let atn = losing_alternative_action_atn();
20349        let mut parser = mini_parser_with_hooks(
20350            vec![
20351                TestToken::new(2).with_text("y"),
20352                TestToken::eof("parser-test", 1, 1, 1),
20353            ],
20354            StatefulActionHooks::default(),
20355        );
20356
20357        let (tree, deferred_actions) = parser
20358            .parse_atn_rule_with_runtime_options(
20359                &atn,
20360                0,
20361                ParserRuntimeOptions {
20362                    action_indices: &[(2, 0)],
20363                    ..ParserRuntimeOptions::default()
20364                },
20365            )
20366            .expect("the token-led second alternative should be selected");
20367
20368        assert_eq!(parser.node(tree).text(), "y");
20369        assert!(deferred_actions.is_empty());
20370        assert!(parser.semantic_hooks.events.is_empty());
20371    }
20372
20373    #[test]
20374    fn committed_walker_honors_decision_overrides() {
20375        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20376        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
20377        let mut parser = mini_parser_with_hooks(
20378            vec![
20379                TestToken::new(1).with_text("x"),
20380                TestToken::eof("parser-test", 1, 1, 1),
20381            ],
20382            ForcedSecondAlternativeHooks::default(),
20383        );
20384
20385        let (tree, deferred_actions) = parser
20386            .parse_atn_rule_with_runtime_options(
20387                &atn,
20388                0,
20389                ParserRuntimeOptions {
20390                    action_indices: &[(usize::MAX, 0)],
20391                    track_alt_numbers: true,
20392                    predicates: &predicates,
20393                    ..ParserRuntimeOptions::default()
20394                },
20395            )
20396            .expect("the forced second alternative should parse");
20397
20398        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20399        assert_eq!(root.alt_number(), 2);
20400        assert_eq!(root.text(), "x<EOF>");
20401        assert!(deferred_actions.is_empty());
20402        assert_eq!(parser.semantic_hooks.decisions, [(0, 0, 2)]);
20403        assert_eq!(parser.number_of_syntax_errors(), 0);
20404    }
20405
20406    #[test]
20407    fn committed_walker_sll_mode_does_not_report_full_context_diagnostics() {
20408        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20409        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
20410        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20411        let mut parser = mini_parser(vec![
20412            TestToken::new(1).with_text("x"),
20413            TestToken::eof("parser-test", 1, 1, 1),
20414        ]);
20415        parser.set_prediction_mode(PredictionMode::Sll);
20416        parser.set_report_diagnostic_errors(true);
20417        parser.remove_error_listeners();
20418        parser.add_error_listener(RecordingErrorListener {
20419            diagnostics: Arc::clone(&diagnostics),
20420        });
20421
20422        let (tree, deferred_actions) = parser
20423            .parse_atn_rule_with_runtime_options(
20424                &atn,
20425                0,
20426                ParserRuntimeOptions {
20427                    action_indices: &[(usize::MAX, 0)],
20428                    predicates: &predicates,
20429                    ..ParserRuntimeOptions::default()
20430                },
20431            )
20432            .expect("SLL prediction should select the first viable alternative");
20433
20434        assert_eq!(parser.node(tree).text(), "x<EOF>");
20435        assert!(deferred_actions.is_empty());
20436        assert_eq!(parser.number_of_syntax_errors(), 0);
20437        assert!(
20438            diagnostics
20439                .lock()
20440                .expect("recorded diagnostics lock")
20441                .is_empty(),
20442            "SLL mode must not retry with full context or report LL diagnostics"
20443        );
20444    }
20445
20446    #[test]
20447    fn committed_sll_containment_conflict_enables_token_deletion_recovery() {
20448        let atn = context_containment_recovery_atn();
20449        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20450        let mut parser = mini_parser_with_hooks(
20451            vec![
20452                TestToken::new(1).with_text("a"),
20453                TestToken::new(2).with_text("b"),
20454                TestToken::new(5).with_text("x"),
20455                TestToken::new(3).with_text("c"),
20456                TestToken::eof("parser-test", 4, 1, 4),
20457            ],
20458            ContainmentRecoveryHooks::default(),
20459        );
20460        parser.set_prediction_mode(PredictionMode::Sll);
20461        parser.remove_error_listeners();
20462        parser.add_error_listener(RecordingErrorListener {
20463            diagnostics: Arc::clone(&diagnostics),
20464        });
20465
20466        let (tree, deferred_actions) = parser
20467            .parse_atn_rule_with_runtime_options(
20468                &atn,
20469                0,
20470                ParserRuntimeOptions {
20471                    action_indices: &[(usize::MAX, 0)],
20472                    ..ParserRuntimeOptions::default()
20473                },
20474            )
20475            .expect("the selected alternative should recover by deleting token x");
20476
20477        assert!(deferred_actions.is_empty());
20478        assert_eq!(parser.node(tree).text(), "abxc<EOF>");
20479        assert_eq!(parser.number_of_syntax_errors(), 1);
20480        assert_eq!(parser.semantic_hooks.decisions, [(0, 0, 2), (1, 0, 2)]);
20481        insta::assert_debug_snapshot!(
20482            "committed_sll_containment_conflict_enables_token_deletion_recovery",
20483            diagnostics
20484                .lock()
20485                .expect("recorded diagnostics lock")
20486                .as_slice()
20487        );
20488    }
20489
20490    #[test]
20491    fn committed_walker_filters_diagnostics_after_semantic_selection() {
20492        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20493        let predicates = [
20494            (0, 0, ParserPredicate::False),
20495            (0, 1, ParserPredicate::True),
20496        ];
20497        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20498        let mut parser = mini_parser(vec![
20499            TestToken::new(1).with_text("x"),
20500            TestToken::eof("parser-test", 1, 1, 1),
20501        ]);
20502        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20503        parser.set_report_diagnostic_errors(true);
20504        parser.remove_error_listeners();
20505        parser.add_error_listener(RecordingErrorListener {
20506            diagnostics: Arc::clone(&diagnostics),
20507        });
20508
20509        let (tree, _) = parser
20510            .parse_atn_rule_with_runtime_options(
20511                &atn,
20512                0,
20513                ParserRuntimeOptions {
20514                    action_indices: &[(usize::MAX, 0)],
20515                    track_alt_numbers: true,
20516                    predicates: &predicates,
20517                    ..ParserRuntimeOptions::default()
20518                },
20519            )
20520            .expect("the true predicate should make the second alternative unique");
20521
20522        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20523        assert_eq!(root.alt_number(), 2);
20524        assert!(
20525            diagnostics
20526                .lock()
20527                .expect("recorded diagnostics lock")
20528                .is_empty(),
20529            "predicate filtering made the decision unambiguous"
20530        );
20531    }
20532
20533    #[test]
20534    fn committed_walker_skips_diagnostic_only_predicates_when_reporting_is_disabled() {
20535        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20536        let mut parser = mini_parser_with_hooks(
20537            vec![
20538                TestToken::new(1).with_text("x"),
20539                TestToken::eof("parser-test", 1, 1, 1),
20540            ],
20541            RecordingHooks::default(),
20542        );
20543        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20544
20545        let (tree, _) = parser
20546            .parse_atn_rule_with_runtime_options(
20547                &atn,
20548                0,
20549                ParserRuntimeOptions {
20550                    action_indices: &[(usize::MAX, 0)],
20551                    track_alt_numbers: true,
20552                    ..ParserRuntimeOptions::default()
20553                },
20554            )
20555            .expect("the first predicate-bearing alternative should parse");
20556
20557        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20558        assert_eq!(root.alt_number(), 1);
20559        assert_eq!(
20560            parser.semantic_hooks.predicates,
20561            [
20562                (0, 0, 0, Some("x".to_owned())),
20563                (0, 0, 0, Some("x".to_owned())),
20564            ],
20565            "diagnostic-only alternatives must not invoke semantic hooks"
20566        );
20567    }
20568
20569    #[test]
20570    fn committed_walker_falls_back_only_to_simulator_viable_alternatives() {
20571        let atn = semantic_fallback_viability_atn();
20572        let predicates = [
20573            (0, 0, ParserPredicate::False),
20574            (0, 1, ParserPredicate::True),
20575        ];
20576        let mut parser = mini_parser(vec![
20577            TestToken::new(1).with_text("a"),
20578            TestToken::new(3).with_text("c"),
20579            TestToken::eof("parser-test", 2, 1, 2),
20580        ]);
20581
20582        let (tree, deferred_actions) = parser
20583            .parse_atn_rule_with_runtime_options(
20584                &atn,
20585                0,
20586                ParserRuntimeOptions {
20587                    action_indices: &[(usize::MAX, 0)],
20588                    track_alt_numbers: true,
20589                    predicates: &predicates,
20590                    ..ParserRuntimeOptions::default()
20591                },
20592            )
20593            .expect("the true A C alternative should survive semantic fallback");
20594
20595        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20596        assert_eq!(root.alt_number(), 3);
20597        assert_eq!(root.text(), "ac<EOF>");
20598        assert!(deferred_actions.is_empty());
20599        assert_eq!(parser.number_of_syntax_errors(), 0);
20600    }
20601
20602    #[test]
20603    fn committed_walker_evaluates_predicates_reached_through_rule_calls() {
20604        let atn = rule_call_predicate_decision_atn();
20605        let predicates = [(1, 0, ParserPredicate::False)];
20606        let mut parser = mini_parser(vec![
20607            TestToken::new(1).with_text("a"),
20608            TestToken::eof("parser-test", 1, 1, 1),
20609        ]);
20610
20611        let (tree, deferred_actions) = parser
20612            .parse_atn_rule_with_runtime_options(
20613                &atn,
20614                0,
20615                ParserRuntimeOptions {
20616                    action_indices: &[(usize::MAX, 0)],
20617                    track_alt_numbers: true,
20618                    predicates: &predicates,
20619                    ..ParserRuntimeOptions::default()
20620                },
20621            )
20622            .expect("the direct caller alternative should survive the false callee predicate");
20623
20624        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20625        assert_eq!(root.alt_number(), 2);
20626        assert_eq!(root.text(), "a<EOF>");
20627        assert_eq!(root.child_rules(1).count(), 0);
20628        assert!(deferred_actions.is_empty());
20629        assert_eq!(parser.number_of_syntax_errors(), 0);
20630    }
20631
20632    #[test]
20633    fn committed_walker_uses_callee_argument_for_prediction_predicates() {
20634        let atn = rule_call_predicate_decision_atn();
20635        let predicates = [(1, 0, ParserPredicate::LocalIntEquals { value: 1 })];
20636        let rule_args = [ParserRuleArg {
20637            source_state: 2,
20638            rule_index: 1,
20639            value: 2,
20640            inherit_local: false,
20641        }];
20642        let mut parser = mini_parser(vec![
20643            TestToken::new(1).with_text("a"),
20644            TestToken::eof("parser-test", 1, 1, 1),
20645        ]);
20646
20647        let (tree, _) = parser
20648            .parse_atn_rule_with_runtime_options(
20649                &atn,
20650                0,
20651                ParserRuntimeOptions {
20652                    action_indices: &[(usize::MAX, 0)],
20653                    track_alt_numbers: true,
20654                    predicates: &predicates,
20655                    rule_args: &rule_args,
20656                    ..ParserRuntimeOptions::default()
20657                },
20658            )
20659            .expect("the direct alternative should survive the false callee predicate");
20660
20661        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20662        assert_eq!(root.alt_number(), 2);
20663        assert_eq!(root.child_rules(1).count(), 0);
20664        assert_eq!(parser.number_of_syntax_errors(), 0);
20665    }
20666
20667    #[test]
20668    fn committed_predicate_star_loop_uses_single_token_deletion() {
20669        let atn = predicate_gated_star_loop_atn();
20670        let predicates = [(0, 0, ParserPredicate::True)];
20671        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20672        let mut parser = mini_parser(vec![
20673            TestToken::new(2).with_text("x"),
20674            TestToken::new(1).with_text("a"),
20675            TestToken::eof("parser-test", 2, 1, 2),
20676        ]);
20677        parser.remove_error_listeners();
20678        parser.add_error_listener(RecordingErrorListener {
20679            diagnostics: Arc::clone(&diagnostics),
20680        });
20681
20682        let (tree, deferred_actions) = parser
20683            .parse_atn_rule_with_runtime_options(
20684                &atn,
20685                0,
20686                ParserRuntimeOptions {
20687                    action_indices: &[(usize::MAX, 0)],
20688                    predicates: &predicates,
20689                    ..ParserRuntimeOptions::default()
20690                },
20691            )
20692            .expect("the loop decision should delete the extraneous token and continue");
20693
20694        assert_eq!(parser.node(tree).text(), "xa<EOF>");
20695        assert!(deferred_actions.is_empty());
20696        assert_eq!(parser.number_of_syntax_errors(), 1);
20697        insta::assert_debug_snapshot!(
20698            "committed_predicate_star_loop_uses_single_token_deletion",
20699            *diagnostics.lock().expect("recorded diagnostics lock")
20700        );
20701    }
20702
20703    #[test]
20704    fn committed_walker_applies_legacy_and_semir_actions_before_indexed_hooks() {
20705        let atn = committed_action_then_predicate_atn();
20706        let member_actions = [ParserMemberAction {
20707            source_state: 0,
20708            member: 0,
20709            delta: 2,
20710        }];
20711        let return_actions = [ParserReturnAction {
20712            source_state: 0,
20713            rule_index: 0,
20714            name: "legacy",
20715            value: 3,
20716        }];
20717        let predicates = [(
20718            0,
20719            0,
20720            ParserPredicate::MemberEquals {
20721                member: 0,
20722                value: 7,
20723                equals: true,
20724            },
20725        )];
20726        let mut ir = SemIr::new();
20727        let semantic_member = ParserMemberAction {
20728            source_state: 0,
20729            member: 0,
20730            delta: 5,
20731        }
20732        .lower_into_semir(&mut ir);
20733        let semantic_return = ParserReturnAction {
20734            source_state: 0,
20735            rule_index: 0,
20736            name: "semantic",
20737            value: 11,
20738        }
20739        .lower_into_semir(&mut ir);
20740        let semantics = ParserSemantics {
20741            ir,
20742            predicates: Vec::new(),
20743            actions: vec![semantic_member, semantic_return],
20744        };
20745        let mut parser = mini_parser_with_hooks(
20746            vec![
20747                TestToken::new(1).with_text("x"),
20748                TestToken::eof("parser-test", 1, 1, 1),
20749            ],
20750            StatefulActionHooks::default(),
20751        );
20752
20753        let (tree, deferred_actions) = parser
20754            .parse_atn_rule_with_runtime_options(
20755                &atn,
20756                0,
20757                ParserRuntimeOptions {
20758                    action_indices: &[(0, 7)],
20759                    predicates: &predicates,
20760                    semantics: Some(&semantics),
20761                    member_actions: &member_actions,
20762                    return_actions: &return_actions,
20763                    ..ParserRuntimeOptions::default()
20764                },
20765            )
20766            .expect("the predicate should observe both committed member actions");
20767
20768        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20769        assert_eq!(root.text(), "x<EOF>");
20770        assert_eq!(root.int_return("legacy"), Some(3));
20771        assert_eq!(root.int_return("semantic"), Some(11));
20772        assert_eq!(parser.int_member(0), Some(7));
20773        assert!(deferred_actions.is_empty());
20774        assert_eq!(parser.semantic_hooks.events, ["action:7"]);
20775        assert_eq!(parser.number_of_syntax_errors(), 0);
20776    }
20777
20778    #[test]
20779    fn committed_walker_runs_action_once_per_star_loop_iteration() {
20780        let atn = committed_action_star_loop_atn();
20781        let mut parser = mini_parser_with_hooks(
20782            vec![
20783                TestToken::new(1).with_text("a"),
20784                TestToken::new(1).with_text("b"),
20785                TestToken::eof("parser-test", 2, 1, 2),
20786            ],
20787            StatefulActionHooks::default(),
20788        );
20789
20790        let (tree, deferred_actions) = parser
20791            .parse_atn_rule_with_runtime_options(
20792                &atn,
20793                0,
20794                ParserRuntimeOptions {
20795                    action_indices: &[(2, 3)],
20796                    ..ParserRuntimeOptions::default()
20797                },
20798            )
20799            .expect("the committed star loop should parse");
20800
20801        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20802        assert!(deferred_actions.is_empty());
20803        assert_eq!(parser.semantic_hooks.events, ["action:3", "action:3"]);
20804    }
20805
20806    #[test]
20807    fn committed_walker_has_no_total_step_cap() {
20808        const TOKEN_COUNT: usize = RECOGNITION_DEPTH_LIMIT + 1;
20809        let atn = committed_action_star_loop_atn();
20810        let mut parser = mini_parser(repeated_x_tokens(TOKEN_COUNT));
20811        parser.set_build_parse_trees(false);
20812
20813        parser
20814            .parse_atn_rule_with_runtime_options(
20815                &atn,
20816                0,
20817                ParserRuntimeOptions {
20818                    action_indices: &[(usize::MAX, 0)],
20819                    ..ParserRuntimeOptions::default()
20820                },
20821            )
20822            .expect("valid committed loops must not have a total-work cap");
20823
20824        assert_eq!(parser.input.index(), TOKEN_COUNT);
20825        assert_eq!(parser.number_of_syntax_errors(), 0);
20826    }
20827
20828    #[test]
20829    fn committed_walker_rejects_non_consuming_cycles() {
20830        let atn = committed_non_consuming_cycle_atn();
20831        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
20832        parser.set_bail_on_error(true);
20833
20834        let error = parser
20835            .parse_atn_rule_with_runtime_options(
20836                &atn,
20837                0,
20838                ParserRuntimeOptions {
20839                    action_indices: &[(usize::MAX, 0)],
20840                    ..ParserRuntimeOptions::default()
20841                },
20842            )
20843            .expect_err("a non-consuming cycle must not spin forever");
20844
20845        assert!(
20846            error.to_string().contains("non-consuming ATN cycle"),
20847            "unexpected error: {error}"
20848        );
20849    }
20850
20851    #[test]
20852    fn deeply_nested_committed_rule_calls_grow_the_stack() {
20853        const DEPTH: usize = 4_096;
20854        const STACK_SIZE: usize = 256 * 1024;
20855        let atn = nested_rule_chain_atn(DEPTH);
20856        std::thread::Builder::new()
20857            .name("nested-committed-rules".to_owned())
20858            .stack_size(STACK_SIZE)
20859            .spawn(move || {
20860                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
20861                parser.set_build_parse_trees(false);
20862                parser
20863                    .parse_atn_rule_with_runtime_options(
20864                        &atn,
20865                        0,
20866                        ParserRuntimeOptions {
20867                            action_indices: &[(usize::MAX, 0)],
20868                            ..ParserRuntimeOptions::default()
20869                        },
20870                    )
20871                    .expect("nested committed rules should grow the native stack");
20872                assert_eq!(parser.input.index(), 1);
20873            })
20874            .expect("small-stack thread should start")
20875            .join()
20876            .expect("nested committed rules should not overflow their stack");
20877    }
20878
20879    #[test]
20880    fn committed_walker_runs_action_once_per_left_recursive_operator() {
20881        let atn = committed_action_left_recursive_atn();
20882        let mut parser = mini_parser_with_hooks(
20883            vec![
20884                TestToken::new(1).with_text("a"),
20885                TestToken::new(3).with_text("+"),
20886                TestToken::new(1).with_text("b"),
20887                TestToken::new(3).with_text("+"),
20888                TestToken::new(1).with_text("c"),
20889                TestToken::eof("parser-test", 5, 1, 5),
20890            ],
20891            StatefulActionHooks::default(),
20892        );
20893
20894        let (tree, deferred_actions) = parser
20895            .parse_atn_rule_with_runtime_options(
20896                &atn,
20897                0,
20898                ParserRuntimeOptions {
20899                    action_indices: &[(6, 11)],
20900                    ..ParserRuntimeOptions::default()
20901                },
20902            )
20903            .expect("the committed left-recursive rule should parse");
20904
20905        assert_eq!(parser.node(tree).text(), "a+b+c");
20906        assert!(deferred_actions.is_empty());
20907        assert_eq!(parser.semantic_hooks.events, ["action:11", "action:11"]);
20908    }
20909
20910    #[test]
20911    fn committed_left_recursive_depth_cap_keeps_listener_events_balanced() {
20912        let atn = committed_action_left_recursive_atn();
20913        let events = Arc::new(Mutex::new(Vec::new()));
20914        let mut parser = mini_parser(vec![
20915            TestToken::new(1).with_text("a"),
20916            TestToken::new(3).with_text("+"),
20917            TestToken::new(1).with_text("b"),
20918            TestToken::eof("parser-test", 3, 1, 3),
20919        ]);
20920        parser.set_max_rule_depth(Some(1));
20921        parser.add_parse_listener(RecordingParseListener {
20922            events: Arc::clone(&events),
20923        });
20924
20925        let error = parser
20926            .parse_atn_rule_with_runtime_options(
20927                &atn,
20928                0,
20929                ParserRuntimeOptions {
20930                    action_indices: &[(6, 11)],
20931                    ..ParserRuntimeOptions::default()
20932                },
20933            )
20934            .expect_err("the left-recursive expansion should exceed the depth cap");
20935
20936        insta::assert_debug_snapshot!(
20937            "committed_left_recursive_depth_cap_keeps_listener_events_balanced",
20938            (
20939                error.to_string(),
20940                events.lock().expect("parse-listener event lock").as_slice(),
20941            )
20942        );
20943    }
20944
20945    #[test]
20946    fn committed_walker_preserves_nested_rule_listener_events() {
20947        let atn = ordinary_star_loop_atn();
20948        let events = Arc::new(Mutex::new(Vec::new()));
20949        let mut parser = mini_parser(vec![
20950            TestToken::new(1).with_text("a"),
20951            TestToken::new(1).with_text("b"),
20952            TestToken::eof("parser-test", 2, 1, 2),
20953        ]);
20954        parser.add_parse_listener(RecordingParseListener {
20955            events: Arc::clone(&events),
20956        });
20957
20958        let (tree, _) = parser
20959            .parse_atn_rule_with_runtime_options(
20960                &atn,
20961                0,
20962                ParserRuntimeOptions {
20963                    action_indices: &[(usize::MAX, 0)],
20964                    ..ParserRuntimeOptions::default()
20965                },
20966            )
20967            .expect("the committed nested-rule path should parse");
20968
20969        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20970        assert_eq!(
20971            *events.lock().expect("parse-listener event lock"),
20972            [
20973                "enter:0", "enter:1", "exit:1", "enter:1", "exit:1", "exit:0",
20974            ]
20975        );
20976    }
20977
20978    #[test]
20979    fn committed_walker_enforces_rule_depth_cap() {
20980        let atn = ordinary_star_loop_atn();
20981        let mut parser = mini_parser(vec![
20982            TestToken::new(1).with_text("a"),
20983            TestToken::eof("parser-test", 1, 1, 1),
20984        ]);
20985        parser.set_max_rule_depth(Some(1));
20986
20987        let error = parser
20988            .parse_atn_rule_with_runtime_options(
20989                &atn,
20990                0,
20991                ParserRuntimeOptions {
20992                    action_indices: &[(usize::MAX, 0)],
20993                    ..ParserRuntimeOptions::default()
20994                },
20995            )
20996            .expect_err("the nested rule should exceed the committed-path cap");
20997
20998        assert!(
20999            error
21000                .to_string()
21001                .contains("rule nesting depth limit of 1 exceeded"),
21002            "unexpected error: {error}"
21003        );
21004    }
21005
21006    #[test]
21007    fn committed_abort_precedes_and_clears_unhandled_action_error() {
21008        let atn = action_then_nested_rule_atn();
21009        let mut parser = mini_parser_with_hooks(
21010            vec![TestToken::eof("parser-test", 0, 1, 0)],
21011            DecliningActionHooks::default(),
21012        );
21013        parser.set_max_rule_depth(Some(1));
21014
21015        let error = parser
21016            .parse_atn_rule_with_runtime_options(
21017                &atn,
21018                0,
21019                ParserRuntimeOptions {
21020                    action_indices: &[(0, 7)],
21021                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21022                    ..ParserRuntimeOptions::default()
21023                },
21024            )
21025            .expect_err("the recovered child abort must outrank the earlier action miss");
21026
21027        assert_eq!(parser.semantic_hooks.actions, [0]);
21028        assert!(
21029            error
21030                .to_string()
21031                .contains("rule nesting depth limit of 1 exceeded"),
21032            "unexpected error: {error}"
21033        );
21034        assert!(
21035            parser.take_parse_abort().is_none(),
21036            "the returned abort must not remain sticky"
21037        );
21038        assert!(
21039            parser.take_unknown_semantic_error().is_none(),
21040            "the masked action miss must not poison parser reuse"
21041        );
21042    }
21043
21044    #[test]
21045    fn top_level_committed_semantic_error_does_not_poison_reuse() {
21046        let atn = committed_action_then_predicate_atn();
21047        let predicates = [(0, 0, ParserPredicate::True)];
21048        let mut parser = mini_parser_with_hooks(
21049            vec![
21050                TestToken::new(1).with_text("x"),
21051                TestToken::eof("parser-test", 1, 1, 1),
21052            ],
21053            DecliningActionHooks::default(),
21054        );
21055
21056        let error = parser
21057            .parse_atn_rule_with_runtime_options(
21058                &atn,
21059                0,
21060                ParserRuntimeOptions {
21061                    action_indices: &[(0, 7)],
21062                    predicates: &predicates,
21063                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21064                    ..ParserRuntimeOptions::default()
21065                },
21066            )
21067            .expect_err("the declined committed action must fail loud");
21068        assert!(
21069            error.to_string().contains("unhandled semantic action"),
21070            "unexpected error: {error}"
21071        );
21072
21073        parser.input.seek(0);
21074        let (tree, _) = parser
21075            .parse_atn_rule_with_runtime_options(
21076                &atn,
21077                0,
21078                ParserRuntimeOptions {
21079                    predicates: &predicates,
21080                    ..ParserRuntimeOptions::default()
21081                },
21082            )
21083            .expect("a clean interpreted reuse must not observe the prior action miss");
21084
21085        assert_eq!(parser.node(tree).text(), "x<EOF>");
21086        assert!(
21087            parser.take_unknown_semantic_error().is_none(),
21088            "the returned top-level semantic error must drain its recorded hit"
21089        );
21090    }
21091
21092    #[test]
21093    fn committed_walker_runs_handled_rule_init_before_indexed_action() {
21094        let atn = committed_action_then_predicate_atn();
21095        let mut parser = mini_parser_with_hooks(
21096            vec![
21097                TestToken::new(1).with_text("x"),
21098                TestToken::eof("parser-test", 1, 1, 1),
21099            ],
21100            InitOrderingHooks::default(),
21101        );
21102
21103        let (_, deferred_actions) = parser
21104            .parse_atn_rule_with_runtime_options(
21105                &atn,
21106                0,
21107                ParserRuntimeOptions {
21108                    init_action_rules: &[0],
21109                    action_indices: &[(0, 7)],
21110                    ..ParserRuntimeOptions::default()
21111                },
21112            )
21113            .expect("the named action should observe rule-init state");
21114
21115        assert!(deferred_actions.is_empty());
21116        assert_eq!(
21117            parser.semantic_hooks.events,
21118            ["init", "action:7:initialized=true", "predicate:true",]
21119        );
21120    }
21121
21122    #[test]
21123    fn committed_walker_defers_unhandled_rule_init_for_legacy_replay() {
21124        let atn = token_then_eof_atn();
21125        let mut parser = mini_parser(vec![
21126            TestToken::new(1).with_text("x"),
21127            TestToken::eof("parser-test", 1, 1, 1),
21128        ]);
21129
21130        let (_, deferred_actions) = parser
21131            .parse_atn_rule_with_runtime_options(
21132                &atn,
21133                0,
21134                ParserRuntimeOptions {
21135                    init_action_rules: &[0],
21136                    action_indices: &[(usize::MAX, 0)],
21137                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21138                    ..ParserRuntimeOptions::default()
21139                },
21140            )
21141            .expect("a declined init should remain available for legacy replay");
21142
21143        assert_eq!(
21144            deferred_actions,
21145            [ParserAction::new_rule_init(0, 0, Some(0))]
21146        );
21147    }
21148
21149    #[test]
21150    fn committed_walker_dispatches_recovery_diagnostics() {
21151        let atn = noop_action_then_token_then_eof_atn();
21152        let diagnostics = Arc::new(Mutex::new(Vec::new()));
21153        let mut parser = mini_parser_with_hooks(
21154            vec![
21155                TestToken::new(1).with_text("x"),
21156                TestToken::new(2).with_text("y"),
21157                TestToken::eof("parser-test", 2, 1, 2),
21158            ],
21159            StatefulActionHooks::default(),
21160        );
21161        parser.remove_error_listeners();
21162        parser.add_error_listener(RecordingErrorListener {
21163            diagnostics: Arc::clone(&diagnostics),
21164        });
21165
21166        let (tree, _) = parser
21167            .parse_atn_rule_with_runtime_options(
21168                &atn,
21169                0,
21170                ParserRuntimeOptions {
21171                    action_indices: &[(0, 5)],
21172                    ..ParserRuntimeOptions::default()
21173                },
21174            )
21175            .expect("the committed rule should recover");
21176
21177        assert_eq!(parser.node(tree).text(), "xy<EOF>");
21178        assert_eq!(parser.number_of_syntax_errors(), 1);
21179        insta::assert_debug_snapshot!(
21180            "committed_walker_dispatches_recovery_diagnostics",
21181            *diagnostics.lock().expect("recorded diagnostics lock")
21182        );
21183    }
21184
21185    #[test]
21186    fn committed_bail_error_notifies_error_listener() {
21187        let atn = noop_action_then_token_then_eof_atn();
21188        let diagnostics = Arc::new(Mutex::new(Vec::new()));
21189        let mut parser = mini_parser(vec![
21190            TestToken::new(2)
21191                .with_text("y")
21192                .with_span(0, 0)
21193                .with_byte_span(0, 1)
21194                .with_position(3, 5),
21195            TestToken::eof("parser-test", 1, 1, 1),
21196        ]);
21197        parser.set_bail_on_error(true);
21198        parser.remove_error_listeners();
21199        parser.add_error_listener(RecordingErrorListener {
21200            diagnostics: Arc::clone(&diagnostics),
21201        });
21202
21203        let error = parser
21204            .parse_atn_rule_with_runtime_options(
21205                &atn,
21206                0,
21207                ParserRuntimeOptions {
21208                    action_indices: &[(0, 5)],
21209                    ..ParserRuntimeOptions::default()
21210                },
21211            )
21212            .expect_err("bail mode must return the committed token mismatch");
21213        let diagnostics = diagnostics
21214            .lock()
21215            .expect("recorded diagnostics lock")
21216            .clone();
21217
21218        insta::assert_debug_snapshot!(
21219            "committed_bail_error_notifies_error_listener",
21220            (error, diagnostics)
21221        );
21222    }
21223
21224    #[test]
21225    fn semantic_hook_handles_committed_parser_action() {
21226        let atn = token_then_eof_atn();
21227        let mut parser = mini_parser_with_hooks(
21228            vec![
21229                TestToken::new(1).with_text("x"),
21230                TestToken::eof("parser-test", 1, 1, 1),
21231            ],
21232            RecordingHooks::default(),
21233        );
21234        let (tree, _) = parser
21235            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
21236            .expect("rule parses before action hook is tested");
21237
21238        assert!(parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
21239        assert_eq!(
21240            parser.semantic_hooks.actions,
21241            vec![(42, "x".to_owned(), Some("s".to_owned()))]
21242        );
21243        assert_eq!(
21244            parser.semantic_hooks.action_trees,
21245            [Some("x<EOF>".to_owned())]
21246        );
21247    }
21248
21249    #[test]
21250    fn unhandled_committed_action_fails_loud_under_error_policy() {
21251        // An action offered to the hook that no hook handles (returns false)
21252        // must be recorded and surfaced as `AntlrError::Unsupported` under the
21253        // Error policy, so a `hook`-disposed action is not silently dropped.
21254        let mut parser = mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21255        parser.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
21256        let tree = parser.rule_node(ParserRuleContext::new(0, -1));
21257
21258        // DecliningHooks::action returns false (unhandled).
21259        assert!(!parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
21260
21261        let error = parser
21262            .take_unknown_semantic_error()
21263            .expect("an unhandled committed action under Error policy must fail loud");
21264        let AntlrError::Unsupported(message) = error else {
21265            panic!("expected AntlrError::Unsupported, got {error:?}");
21266        };
21267        assert!(
21268            message.contains("unhandled semantic action") && message.contains("state=42"),
21269            "message should name the dropped action coordinate: {message}"
21270        );
21271
21272        // Under the default (assume-true) policy the same miss is not recorded.
21273        let mut lenient =
21274            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21275        let tree = lenient.rule_node(ParserRuleContext::new(0, -1));
21276        assert!(!lenient.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
21277        assert!(lenient.take_unknown_semantic_error().is_none());
21278    }
21279
21280    #[test]
21281    fn translated_predicate_is_unaffected_by_error_policy() {
21282        let atn = predicate_after_token_atn();
21283        let mut parser = mini_parser(vec![
21284            TestToken::new(1).with_text("x"),
21285            TestToken::new(2).with_text("y"),
21286            TestToken::eof("parser-test", 2, 1, 2),
21287        ]);
21288
21289        let (tree, _) = parser
21290            .parse_atn_rule_with_runtime_options(
21291                &atn,
21292                0,
21293                ParserRuntimeOptions {
21294                    predicates: &[(0, 0, ParserPredicate::True)],
21295                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21296                    ..ParserRuntimeOptions::default()
21297                },
21298            )
21299            .expect("a predicate covered by the table is not an unknown coordinate");
21300
21301        assert_eq!(parser.node(tree).text(), "xy");
21302    }
21303
21304    /// Stack-valued member statements must execute on the parser's speculative
21305    /// replay path, not just the lexer's committed one (issue #206). This drives
21306    /// `apply_member_actions` -> `ParserTableSemCtx` -> `MemberEnv` directly,
21307    /// which is the path a generated parser's `@members` stack state takes.
21308    #[test]
21309    fn parser_speculative_replay_threads_stack_member_state() {
21310        let mut ir = SemIr::new();
21311        let one = ir.expr(PExpr::Int(1));
21312        let push = ir.stmt(AStmt::PushMember(0, one));
21313        let pop = ir.stmt(AStmt::PopMember(0));
21314        let semantics = ParserSemantics {
21315            ir,
21316            predicates: Vec::new(),
21317            actions: vec![
21318                ParserSemanticAction {
21319                    source_state: 1,
21320                    rule_index: usize::MAX,
21321                    stmt: push,
21322                    speculative: true,
21323                },
21324                ParserSemanticAction {
21325                    source_state: 2,
21326                    rule_index: usize::MAX,
21327                    stmt: pop,
21328                    speculative: true,
21329                },
21330            ],
21331        };
21332
21333        // Replaying the push state must be visible to a later read...
21334        let pushed = member_values_after_action(1, &[], Some(&semantics), &MemberEnv::new());
21335        assert_eq!(pushed.stack_top(0), Some(1));
21336        assert_eq!(pushed.stack_len(0), 1);
21337
21338        // ...and must not mutate the caller's env: speculative paths are
21339        // path-local, so an abandoned branch cannot leak state to its sibling.
21340        assert_eq!(MemberEnv::new().stack_len(0), 0);
21341
21342        // Replaying the pop state restores the empty, canonical env, so the
21343        // resulting memo key matches an equivalent untouched path.
21344        let popped = member_values_after_action(2, &[], Some(&semantics), &pushed);
21345        assert_eq!(popped.stack_top(0), None);
21346        assert_eq!(popped, MemberEnv::new(), "emptied stack must canonicalize");
21347
21348        // An unbalanced pop is a defined no-op rather than a panic.
21349        let underflowed = member_values_after_action(2, &[], Some(&semantics), &MemberEnv::new());
21350        assert_eq!(underflowed, MemberEnv::new());
21351    }
21352
21353    /// Hooks that decline (`None`) must fall through to the configured policy
21354    /// even when the coordinate carries a [`semir`] `Hook` node, matching the
21355    /// legacy table path. Regression for the `unwrap_or(false)` that silently
21356    /// rejected declined hook nodes and bypassed [`UnknownSemanticPolicy`].
21357    fn hook_predicate_semantics() -> ParserSemantics {
21358        let mut ir = SemIr::new();
21359        let expr = ir.expr(PExpr::Hook(HookId::new(0)));
21360        ParserSemantics {
21361            ir,
21362            predicates: vec![ParserSemanticPredicate {
21363                rule_index: 0,
21364                pred_index: 0,
21365                expr,
21366                failure_message: None,
21367            }],
21368            actions: Vec::new(),
21369        }
21370    }
21371
21372    #[derive(Debug, Default)]
21373    struct DecliningHooks;
21374
21375    impl SemanticHooks for DecliningHooks {}
21376
21377    #[test]
21378    fn semir_hook_none_falls_through_to_assume_true() {
21379        let atn = predicate_after_token_atn();
21380        let semantics = hook_predicate_semantics();
21381        let mut parser = mini_parser_with_hooks(
21382            vec![
21383                TestToken::new(1).with_text("x"),
21384                TestToken::new(2).with_text("y"),
21385                TestToken::eof("parser-test", 2, 1, 2),
21386            ],
21387            DecliningHooks,
21388        );
21389
21390        let (tree, _) = parser
21391            .parse_atn_rule_with_runtime_options(
21392                &atn,
21393                0,
21394                ParserRuntimeOptions {
21395                    semantics: Some(&semantics),
21396                    unknown_predicate_policy: UnknownSemanticPolicy::AssumeTrue,
21397                    ..ParserRuntimeOptions::default()
21398                },
21399            )
21400            .expect("a declined SemIR hook must pass under assume-true");
21401
21402        assert_eq!(parser.node(tree).text(), "xy");
21403    }
21404
21405    #[test]
21406    fn semir_hook_none_falls_through_to_assume_false() {
21407        let atn = predicate_after_token_atn();
21408        let semantics = hook_predicate_semantics();
21409        let mut parser = mini_parser_with_hooks(
21410            vec![
21411                TestToken::new(1).with_text("x"),
21412                TestToken::new(2).with_text("y"),
21413                TestToken::eof("parser-test", 2, 1, 2),
21414            ],
21415            DecliningHooks,
21416        );
21417
21418        let result = parser.parse_atn_rule_with_runtime_options(
21419            &atn,
21420            0,
21421            ParserRuntimeOptions {
21422                semantics: Some(&semantics),
21423                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
21424                ..ParserRuntimeOptions::default()
21425            },
21426        );
21427
21428        assert!(
21429            result.is_err(),
21430            "a declined SemIR hook must fail the only guarded path under assume-false"
21431        );
21432    }
21433
21434    #[test]
21435    fn semir_hook_none_records_coordinate_under_error_policy() {
21436        let atn = predicate_after_token_atn();
21437        let semantics = hook_predicate_semantics();
21438        let mut parser = mini_parser_with_hooks(
21439            vec![
21440                TestToken::new(1).with_text("x"),
21441                TestToken::new(2).with_text("y"),
21442                TestToken::eof("parser-test", 2, 1, 2),
21443            ],
21444            DecliningHooks,
21445        );
21446
21447        let error = parser
21448            .parse_atn_rule_with_runtime_options(
21449                &atn,
21450                0,
21451                ParserRuntimeOptions {
21452                    semantics: Some(&semantics),
21453                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21454                    ..ParserRuntimeOptions::default()
21455                },
21456            )
21457            .expect_err("a declined SemIR hook under Error policy must fail the parse");
21458
21459        let AntlrError::Unsupported(message) = error else {
21460            panic!("expected AntlrError::Unsupported, got {error:?}");
21461        };
21462        assert!(
21463            message.contains("unsupported semantic predicate") && message.contains("pred_index=0"),
21464            "message should name the unresolved coordinate: {message}"
21465        );
21466    }
21467
21468    #[test]
21469    fn generated_direct_predicate_honors_installed_policy() {
21470        // The generated recursive-descent path calls
21471        // `parser_semantic_ir_predicate_matches_with_context_and_local` without
21472        // going through `ParserRuntimeOptions`, so the policy must be installed
21473        // via `set_unknown_predicate_policy` (as the generated constructor now
21474        // does). A declining hook must then honor it rather than the default.
21475        let semantics = hook_predicate_semantics();
21476        let context = ParserRuleContext::new(0, -1);
21477
21478        let mut assume_true =
21479            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21480        assert!(
21481            assume_true.parser_semantic_ir_predicate_matches_with_context_and_local(
21482                &semantics, 0, 0, &context, 0
21483            ),
21484            "default AssumeTrue accepts a declined hook"
21485        );
21486        assert!(assume_true.take_unknown_semantic_error().is_none());
21487
21488        let mut error_policy =
21489            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21490        error_policy.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
21491        assert!(
21492            !error_policy.parser_semantic_ir_predicate_matches_with_context_and_local(
21493                &semantics, 0, 0, &context, 0
21494            ),
21495            "Error policy rejects a declined hook on the generated-direct path"
21496        );
21497        let error = error_policy
21498            .take_unknown_semantic_error()
21499            .expect("Error policy records the unresolved coordinate for the generated path");
21500        let AntlrError::Unsupported(message) = error else {
21501            panic!("expected AntlrError::Unsupported, got {error:?}");
21502        };
21503        assert!(message.contains("pred_index=0"), "message: {message}");
21504    }
21505
21506    #[test]
21507    fn parser_rule_start_skips_leading_hidden_tokens() {
21508        let atn = token_then_eof_atn();
21509        let mut parser = mini_parser(vec![
21510            TestToken::new(99)
21511                .with_text(" ")
21512                .with_channel(HIDDEN_CHANNEL),
21513            TestToken::new(1).with_text("x"),
21514            TestToken::eof("parser-test", 2, 1, 2),
21515        ]);
21516
21517        let tree = parser
21518            .parse_atn_rule(&atn, 0)
21519            .expect("artificial parser rule should parse");
21520        let Some(rule) = parser.node(tree).first_rule(0).and_then(Node::as_rule) else {
21521            panic!("rule node should be present");
21522        };
21523        assert_eq!(
21524            rule.start()
21525                .expect("rule should have a start token")
21526                .token_type(),
21527            1
21528        );
21529    }
21530
21531    #[test]
21532    fn parser_action_after_eof_stops_at_eof_token() {
21533        let atn = eof_then_action_atn();
21534        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
21535
21536        let (_, actions) = parser
21537            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
21538            .expect("EOF action rule should parse");
21539
21540        assert_eq!(actions.len(), 1);
21541        assert_eq!(actions[0].stop_index(), Some(0));
21542        assert_eq!(
21543            parser.text_interval(actions[0].start_index(), actions[0].stop_index()),
21544            ""
21545        );
21546    }
21547
21548    #[test]
21549    fn after_action_stop_uses_rule_context_stop_not_cursor() {
21550        // A rule that ends right before EOF without matching it (e.g. `a: ID;`
21551        // called from `start: a EOF;`): after matching ID the cursor parks on EOF,
21552        // but the rule did not consume it. The @after stop must follow the rule
21553        // context's recorded stop (ID at index 0), not the cursor's EOF (index 1).
21554        let mut id = TestToken::new(1).with_text("x");
21555        id.set_token_index(0);
21556        let mut eof = TestToken::eof("parser-test", 1, 1, 1);
21557        eof.set_token_index(1);
21558        let mut parser = mini_parser(vec![id.clone(), eof]);
21559        // Advance the cursor onto EOF, as it would be after `a` matched ID.
21560        parser.consume();
21561        assert_eq!(parser.la(1), TOKEN_EOF);
21562
21563        // Rule `a` matched only ID, so its context stop is the ID token (index 0),
21564        // exactly what finish_rule(consumed_eof = false) records.
21565        let mut ctx = ParserRuleContext::new(0, 0);
21566        parser.set_context_stop(
21567            &mut ctx,
21568            parser.token_id_at(0).expect("ID token should be buffered"),
21569        );
21570        let tree = parser.rule_node(ctx);
21571
21572        let current_index = parser.input.index();
21573        // Cursor-only inference would wrongly pick EOF (the parked cursor)...
21574        assert_eq!(parser.after_action_stop_index(current_index), Some(1));
21575        // ...but the tree-aware helper follows the rule context stop (ID).
21576        assert_eq!(
21577            parser.after_action_stop_index_for_tree(tree, current_index),
21578            Some(0)
21579        );
21580    }
21581
21582    #[test]
21583    fn after_action_start_uses_rule_context_start_not_cursor() {
21584        // A rule that begins after leading hidden-channel tokens: the rule context
21585        // start (set by `enter_rule`) is the first visible token, not the raw cursor
21586        // that may still point at the hidden prefix. The @after start must follow
21587        // the context start so `$start`/`$text` excludes the hidden prefix.
21588        let mut parser = mini_parser(vec![
21589            TestToken::new(9)
21590                .with_text(" ")
21591                .with_channel(HIDDEN_CHANNEL),
21592            TestToken::new(9)
21593                .with_text(" ")
21594                .with_channel(HIDDEN_CHANNEL),
21595            TestToken::new(1).with_text("x"),
21596            TestToken::eof("parser-test", 3, 1, 3),
21597        ]);
21598
21599        let mut ctx = ParserRuleContext::new(0, 0);
21600        parser.set_context_start(
21601            &mut ctx,
21602            parser.token_id_at(2).expect("ID token should be buffered"),
21603        );
21604        let tree = parser.rule_node(ctx);
21605
21606        // The raw fallback (pre-rule cursor) would be 0 (the hidden prefix)...
21607        // ...but the tree-aware helper follows the rule context start (index 2).
21608        assert_eq!(parser.after_action_start_index_for_tree(tree, 0), 2);
21609
21610        // With no rule start recorded, it falls back to the provided index.
21611        let empty = parser.rule_node(ParserRuleContext::new(0, 0));
21612        assert_eq!(parser.after_action_start_index_for_tree(empty, 7), 7);
21613    }
21614
21615    fn clean_fast_outcome(index: usize, consumed_eof: bool, marker: u32) -> FastRecognizeOutcome {
21616        FastRecognizeOutcome {
21617            index,
21618            consumed_eof,
21619            diagnostics: DiagnosticSeqId::EMPTY,
21620            deferred_nodes: FastDeferredNodeId::EMPTY,
21621            nodes: NodeSeqId(marker),
21622        }
21623    }
21624
21625    #[test]
21626    fn clean_fast_outcome_dedupe_scans_small_lists_inline() {
21627        let mut outcomes = vec![
21628            clean_fast_outcome(4, false, 0),
21629            clean_fast_outcome(2, false, 1),
21630            clean_fast_outcome(4, false, 2),
21631            clean_fast_outcome(4, true, 3),
21632            clean_fast_outcome(2, false, 4),
21633        ];
21634        let mut scratch = FastOutcomeDedupScratch::default();
21635
21636        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21637
21638        assert_eq!(strategy, FastOutcomeDedupStrategy::Inline);
21639        assert_eq!(
21640            outcomes
21641                .iter()
21642                .map(|outcome| (outcome.index, outcome.consumed_eof, outcome.nodes.0))
21643                .collect::<Vec<_>>(),
21644            vec![(4, false, 0), (2, false, 1), (4, true, 3)]
21645        );
21646        assert!(scratch.dense_words.is_empty());
21647        assert!(scratch.sparse_keys.is_empty());
21648    }
21649
21650    #[test]
21651    fn clean_fast_outcome_dedupe_uses_and_reuses_dense_bitmap() {
21652        let mut scratch = FastOutcomeDedupScratch::default();
21653        let mut outcomes = (100..109)
21654            .flat_map(|index| {
21655                [
21656                    clean_fast_outcome(
21657                        index,
21658                        false,
21659                        u32::try_from(index).expect("test index fits in u32"),
21660                    ),
21661                    clean_fast_outcome(index, false, u32::MAX),
21662                ]
21663            })
21664            .collect();
21665
21666        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21667
21668        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21669        assert_eq!(outcomes.len(), 9);
21670        assert_eq!(outcomes[0].nodes, NodeSeqId(100));
21671        let dense_capacity = scratch.dense_words.capacity();
21672
21673        let mut reused = (1_000..1_009)
21674            .map(|index| {
21675                clean_fast_outcome(
21676                    index,
21677                    false,
21678                    u32::try_from(index).expect("test index fits in u32"),
21679                )
21680            })
21681            .collect();
21682        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21683
21684        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21685        assert_eq!(reused.len(), 9);
21686        assert_eq!(scratch.dense_words.capacity(), dense_capacity);
21687    }
21688
21689    #[test]
21690    fn clean_fast_outcome_dedupe_uses_and_reuses_sparse_hash() {
21691        let mut scratch = FastOutcomeDedupScratch::default();
21692        let sparse_indexes = [
21693            0, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000,
21694        ];
21695        let mut outcomes = sparse_indexes
21696            .into_iter()
21697            .chain([400_000])
21698            .enumerate()
21699            .map(|(marker, index)| {
21700                clean_fast_outcome(
21701                    index,
21702                    false,
21703                    u32::try_from(marker).expect("test marker fits in u32"),
21704                )
21705            })
21706            .collect();
21707
21708        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21709
21710        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21711        assert_eq!(outcomes.len(), sparse_indexes.len());
21712        assert_eq!(outcomes[4].nodes, NodeSeqId(4));
21713        let sparse_capacity = scratch.sparse_keys.capacity();
21714
21715        let mut reused = sparse_indexes
21716            .into_iter()
21717            .map(|index| {
21718                clean_fast_outcome(
21719                    index,
21720                    false,
21721                    u32::try_from(index).expect("test index fits in u32"),
21722                )
21723            })
21724            .collect();
21725        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21726
21727        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21728        assert_eq!(reused.len(), sparse_indexes.len());
21729        assert_eq!(scratch.sparse_keys.capacity(), sparse_capacity);
21730    }
21731
21732    #[test]
21733    fn clean_fast_outcome_dedupe_releases_oversized_sparse_hash() {
21734        let mut scratch = FastOutcomeDedupScratch::default();
21735        scratch
21736            .sparse_keys
21737            .reserve(MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS * 2);
21738        assert!(scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21739        let mut outcomes = (0..9)
21740            .map(|index| clean_fast_outcome(index * 100_000, false, index as u32))
21741            .collect();
21742
21743        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21744
21745        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21746        assert!(scratch.sparse_keys.is_empty());
21747        assert!(scratch.sparse_keys.capacity() <= MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21748    }
21749
21750    #[test]
21751    fn fast_outcome_selection_respects_sll_tie_order() {
21752        let mut arena = RecognitionArena::default();
21753        let first = FastRecognizeOutcome {
21754            index: 1,
21755            consumed_eof: false,
21756            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21757                line: 1,
21758                column: 0,
21759                message: "mismatched input 'x'".to_owned(),
21760                offending: None,
21761            }]),
21762            deferred_nodes: FastDeferredNodeId::EMPTY,
21763            nodes: NodeSeqId::EMPTY,
21764        };
21765        let second = FastRecognizeOutcome {
21766            index: first.index,
21767            consumed_eof: first.consumed_eof,
21768            diagnostics: DiagnosticSeqId::EMPTY,
21769            deferred_nodes: FastDeferredNodeId::EMPTY,
21770            nodes: NodeSeqId::EMPTY,
21771        };
21772
21773        let selected = select_best_fast_outcome(
21774            [first, second].into_iter(),
21775            PredictionMode::Sll,
21776            None,
21777            |_| panic!("caller-follow token probe should not run"),
21778            &arena,
21779        )
21780        .expect("one outcome should be selected");
21781        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
21782        let eof_second = FastRecognizeOutcome {
21783            index: second.index,
21784            consumed_eof: true,
21785            diagnostics: DiagnosticSeqId::EMPTY,
21786            deferred_nodes: FastDeferredNodeId::EMPTY,
21787            nodes: NodeSeqId::EMPTY,
21788        };
21789        let selected = select_best_fast_outcome(
21790            [first, eof_second].into_iter(),
21791            PredictionMode::Sll,
21792            None,
21793            |_| panic!("caller-follow token probe should not run"),
21794            &arena,
21795        )
21796        .expect("one outcome should be selected");
21797        assert!(!selected.consumed_eof);
21798        let selected = select_best_fast_outcome(
21799            [first, second].into_iter(),
21800            PredictionMode::Ll,
21801            None,
21802            |_| panic!("caller-follow token probe should not run"),
21803            &arena,
21804        )
21805        .expect("one outcome should be selected");
21806        assert!(selected.diagnostics.is_empty());
21807    }
21808
21809    #[test]
21810    fn recovery_fast_outcome_dedupe_uses_selection_rank() {
21811        let mut arena = RecognitionArena::default();
21812        let first = FastRecognizeOutcome {
21813            index: 3,
21814            consumed_eof: false,
21815            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21816                line: 1,
21817                column: 0,
21818                message: "mismatched input 'x' expecting 'a'".to_owned(),
21819                offending: None,
21820            }]),
21821            deferred_nodes: FastDeferredNodeId::EMPTY,
21822            nodes: NodeSeqId::EMPTY,
21823        };
21824        let same_rank = FastRecognizeOutcome {
21825            index: first.index,
21826            consumed_eof: first.consumed_eof,
21827            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21828                line: 1,
21829                column: 0,
21830                message: "mismatched input 'x' expecting 'b'".to_owned(),
21831                offending: None,
21832            }]),
21833            deferred_nodes: FastDeferredNodeId::EMPTY,
21834            nodes: NodeSeqId::EMPTY,
21835        };
21836        let better_rank = FastRecognizeOutcome {
21837            index: first.index,
21838            consumed_eof: first.consumed_eof,
21839            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21840                line: 1,
21841                column: 0,
21842                message: "missing 'a' at 'x'".to_owned(),
21843                offending: None,
21844            }]),
21845            deferred_nodes: FastDeferredNodeId::EMPTY,
21846            nodes: NodeSeqId::EMPTY,
21847        };
21848        let mut outcomes = vec![first, same_rank, better_rank];
21849
21850        dedupe_fast_outcomes(&mut outcomes, &arena);
21851
21852        assert_eq!(outcomes.len(), 2);
21853        assert_eq!(
21854            arena
21855                .diagnostics(outcomes[0].diagnostics)
21856                .next()
21857                .expect("first diagnostic")
21858                .message,
21859            "mismatched input 'x' expecting 'a'"
21860        );
21861        assert_eq!(
21862            arena
21863                .diagnostics(outcomes[1].diagnostics)
21864                .next()
21865                .expect("second diagnostic")
21866                .message,
21867            "missing 'a' at 'x'"
21868        );
21869    }
21870
21871    #[test]
21872    fn fast_outcome_selection_prefers_generated_caller_follow() {
21873        let arena = RecognitionArena::default();
21874        let earlier = FastRecognizeOutcome {
21875            index: 7,
21876            consumed_eof: false,
21877            diagnostics: DiagnosticSeqId::EMPTY,
21878            deferred_nodes: FastDeferredNodeId::EMPTY,
21879            nodes: NodeSeqId::EMPTY,
21880        };
21881        let later = FastRecognizeOutcome {
21882            index: 8,
21883            consumed_eof: false,
21884            diagnostics: DiagnosticSeqId::EMPTY,
21885            deferred_nodes: FastDeferredNodeId::EMPTY,
21886            nodes: NodeSeqId::EMPTY,
21887        };
21888        let mut follow = TokenBitSet::default();
21889        follow.insert(5);
21890
21891        let selected = select_best_fast_outcome(
21892            [later, earlier].into_iter(),
21893            PredictionMode::Ll,
21894            Some(&follow),
21895            |index| (if index == 7 { 5 } else { TOKEN_EOF }, index == 7, true),
21896            &arena,
21897        )
21898        .expect("one outcome should be selected");
21899        assert_eq!(selected.index, 7);
21900
21901        let selected = select_best_fast_outcome(
21902            [later, earlier].into_iter(),
21903            PredictionMode::Ll,
21904            Some(&follow),
21905            |index| (if index == 7 { 5 } else { TOKEN_EOF }, false, true),
21906            &arena,
21907        )
21908        .expect("one outcome should be selected");
21909        assert_eq!(selected.index, 8);
21910
21911        let indented_next_statement = FastRecognizeOutcome {
21912            index: 9,
21913            consumed_eof: false,
21914            diagnostics: DiagnosticSeqId::EMPTY,
21915            deferred_nodes: FastDeferredNodeId::EMPTY,
21916            nodes: NodeSeqId::EMPTY,
21917        };
21918        let selected = select_best_fast_outcome(
21919            [indented_next_statement, earlier].into_iter(),
21920            PredictionMode::Ll,
21921            Some(&follow),
21922            |index| {
21923                let is_boundary = index == 7;
21924                let is_boundary_gap = matches!(index, 7 | 8);
21925                (
21926                    if index == 7 { 5 } else { TOKEN_EOF },
21927                    is_boundary,
21928                    is_boundary_gap,
21929                )
21930            },
21931            &arena,
21932        )
21933        .expect("one outcome should be selected");
21934        assert_eq!(selected.index, 7);
21935
21936        let continuation = FastRecognizeOutcome {
21937            index: 10,
21938            consumed_eof: false,
21939            diagnostics: DiagnosticSeqId::EMPTY,
21940            deferred_nodes: FastDeferredNodeId::EMPTY,
21941            nodes: NodeSeqId::EMPTY,
21942        };
21943        let selected = select_best_fast_outcome(
21944            [continuation, earlier].into_iter(),
21945            PredictionMode::Ll,
21946            Some(&follow),
21947            |index| {
21948                let is_boundary = matches!(index, 7 | 9);
21949                (
21950                    if index == 7 { 5 } else { TOKEN_EOF },
21951                    is_boundary,
21952                    is_boundary,
21953                )
21954            },
21955            &arena,
21956        )
21957        .expect("one outcome should be selected");
21958        assert_eq!(selected.index, 10);
21959
21960        let selected = select_best_fast_outcome(
21961            [earlier, later].into_iter(),
21962            PredictionMode::Sll,
21963            Some(&follow),
21964            |_| panic!("caller-follow token probe should not run in SLL mode"),
21965            &arena,
21966        )
21967        .expect("one outcome should be selected");
21968        assert_eq!(selected.index, 8);
21969    }
21970
21971    #[test]
21972    fn caller_follow_boundary_text_requires_separator_shape() {
21973        assert!(is_caller_follow_boundary_text(";"));
21974        assert!(is_caller_follow_boundary_text("\n"));
21975        assert!(is_caller_follow_boundary_text("\r\n  "));
21976        assert!(is_caller_follow_boundary_text(";\n"));
21977        assert!(!is_caller_follow_boundary_text("\"\"\"line1\nline2\"\"\""));
21978        assert!(!is_caller_follow_boundary_text("/* line1\nline2 */"));
21979        assert!(!is_caller_follow_boundary_text("identifier"));
21980        assert!(is_caller_follow_boundary_gap_text(" \t "));
21981        assert!(is_caller_follow_boundary_gap_text("\n  "));
21982        assert!(is_caller_follow_boundary_gap_text(";\t"));
21983        assert!(!is_caller_follow_boundary_gap_text(
21984            "\"\"\"line1\nline2\"\"\""
21985        ));
21986        assert!(!is_caller_follow_boundary_gap_text("/* line1\nline2 */"));
21987    }
21988
21989    #[test]
21990    fn caller_follow_token_info_treats_hidden_tokens_as_boundary_gaps() {
21991        let mut parser = mini_parser(vec![
21992            TestToken::new(5).with_text("\n"),
21993            TestToken::new(6)
21994                .with_text("// comment\n")
21995                .with_channel(HIDDEN_CHANNEL),
21996            TestToken::new(1).with_text("x"),
21997            TestToken::eof("parser-test", 1, 2, 0),
21998        ]);
21999
22000        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
22001        assert_eq!(parser.caller_follow_token_info(1), (6, false, true));
22002        assert_eq!(parser.caller_follow_token_info(2), (1, false, false));
22003    }
22004
22005    #[test]
22006    fn caller_follow_token_info_uses_stream_visible_channel() {
22007        let source = Source {
22008            tokens: vec![
22009                TestToken::new(5).with_text("\n").with_channel(2),
22010                TestToken::new(1).with_text("x").with_channel(2),
22011                TestToken::new(6)
22012                    .with_text("// comment\n")
22013                    .with_channel(HIDDEN_CHANNEL),
22014                TestToken::eof("parser-test", 1, 2, 0),
22015            ],
22016            index: 0,
22017        };
22018        let data = RecognizerData::new(
22019            "Mini.g4",
22020            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
22021        );
22022        let mut parser = BaseParser::new(CommonTokenStream::with_channel(source, 2), data);
22023
22024        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
22025        assert_eq!(parser.caller_follow_token_info(1), (1, false, false));
22026        assert_eq!(parser.caller_follow_token_info(2), (6, false, true));
22027    }
22028
22029    #[test]
22030    fn reset_per_parse_caches_clears_state_expected_token_cache() {
22031        let atn = token_then_eof_atn();
22032        let mut parser = mini_parser(Vec::new());
22033
22034        let _ = parser.cached_state_expected_token_set(&atn, 0);
22035        assert!(!parser.state_expected_token_cache.is_empty());
22036
22037        parser.reset_per_parse_caches();
22038        assert!(parser.state_expected_token_cache.is_empty());
22039    }
22040
22041    #[test]
22042    fn empty_cycle_cache_survives_reset_and_invalidates_for_a_different_atn() {
22043        let cyclic = epsilon_cycle_atn();
22044        let acyclic = token_then_eof_atn();
22045        let mut parser = mini_parser(Vec::new());
22046
22047        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
22048        assert_eq!(
22049            parser.empty_cycle_cache_atn,
22050            Some(SharedAtnCacheKey::for_atn(&cyclic))
22051        );
22052        assert_eq!(parser.empty_cycle_cache[1], Some(true));
22053
22054        parser.reset_per_parse_caches();
22055        assert_eq!(parser.empty_cycle_cache[1], Some(true));
22056        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
22057
22058        assert!(!parser.state_can_reenter_without_consuming(&acyclic, 1));
22059        assert_eq!(
22060            parser.empty_cycle_cache_atn,
22061            Some(SharedAtnCacheKey::for_atn(&acyclic))
22062        );
22063        assert_eq!(parser.empty_cycle_cache[1], Some(false));
22064    }
22065
22066    #[test]
22067    fn parser_error_with_empty_expected_set_omits_empty_set_display() {
22068        let source = Source {
22069            tokens: vec![
22070                TestToken::new(1).with_text("x"),
22071                TestToken::eof("parser-test", 1, 1, 1),
22072            ],
22073            index: 0,
22074        };
22075        let data = RecognizerData::new(
22076            "Mini.g4",
22077            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
22078        );
22079        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
22080        let expected = ExpectedTokens {
22081            index: Some(0),
22082            symbols: BTreeSet::new(),
22083            no_viable: None,
22084        };
22085
22086        let (_, message) = parser.expected_error_message(0, 0, &expected);
22087
22088        assert_eq!(message, "mismatched input 'x'");
22089    }
22090
22091    #[test]
22092    fn eof_rule_stop_index_points_at_eof_token() {
22093        let source = Source {
22094            tokens: vec![
22095                TestToken::new(1).with_text("x"),
22096                TestToken::eof("parser-test", 1, 1, 1),
22097            ],
22098            index: 0,
22099        };
22100        let data = RecognizerData::new(
22101            "Mini.g4",
22102            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
22103        );
22104        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
22105
22106        assert_eq!(parser.rule_stop_token_index(1, true), Some(1));
22107        assert_eq!(parser.rule_stop_token_index(1, false), Some(0));
22108    }
22109
22110    #[test]
22111    fn generated_parser_action_uses_current_rule_stop_boundary() {
22112        let mut parser = mini_parser(vec![
22113            TestToken::new(1).with_text("x"),
22114            TestToken::eof("parser-test", 1, 1, 1),
22115        ]);
22116
22117        parser.match_token(1).expect("token should match");
22118        let action = parser.parser_action_at_current(7, 0, 0, false);
22119        assert_eq!(action.source_state(), 7);
22120        assert_eq!(action.rule_index(), 0);
22121        assert_eq!(action.start_index(), 0);
22122        assert_eq!(action.stop_index(), Some(0));
22123
22124        parser.match_eof().expect("EOF should match");
22125        let action = parser.parser_action_at_current(8, 0, 0, true);
22126        assert_eq!(action.stop_index(), Some(1));
22127    }
22128
22129    #[test]
22130    fn folds_left_recursive_boundary_into_rule_node() {
22131        let mut arena = RecognitionArena::default();
22132        let first = arena.push_node(ArenaRecognizedNode::Token {
22133            token: TokenId::try_from(0).expect("test token ID"),
22134        });
22135        let boundary = arena.push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
22136            rule_index: 1,
22137            alt_number: 3,
22138        });
22139        let second = arena.push_node(ArenaRecognizedNode::Token {
22140            token: TokenId::try_from(1).expect("test token ID"),
22141        });
22142        let mut nodes = NodeSeqId::EMPTY;
22143        for node in [first, boundary, second].into_iter().rev() {
22144            nodes = arena.prepend(nodes, node);
22145        }
22146
22147        let folded = arena.fold_left_recursive_boundaries(nodes);
22148        let folded_nodes = arena.iter(folded).collect::<Vec<_>>();
22149
22150        assert_eq!(folded_nodes.len(), 2);
22151        let ArenaRecognizedNode::Rule {
22152            rule_index,
22153            invoking_state,
22154            alt_number,
22155            start_index,
22156            stop_index,
22157            children,
22158            ..
22159        } = arena.node(folded_nodes[0])
22160        else {
22161            panic!("first folded node should be a rule");
22162        };
22163        // The folded rule node's scalar shape (rule/invoking-state/alt/start/stop) is one snapshot;
22164        // child resolution and the sibling identity below stay explicit — a node Debug prints the
22165        // children handle, not the resolved sequence they assert on.
22166        insta::assert_debug_snapshot!(
22167            "folds_left_recursive_boundary_into_rule_node",
22168            (
22169                rule_index,
22170                invoking_state,
22171                alt_number,
22172                start_index,
22173                stop_index
22174            )
22175        );
22176        assert_eq!(arena.iter(children).collect::<Vec<_>>(), [first]);
22177        assert_eq!(arena.node(folded_nodes[1]), arena.node(second));
22178
22179        let stats = arena.stats(folded, DiagnosticSeqId::EMPTY);
22180        assert_eq!(
22181            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
22182            (4, 3, 1)
22183        );
22184        assert_eq!(
22185            (stats.total_links, stats.live_links, stats.dead_links),
22186            (9, 3, 6)
22187        );
22188    }
22189
22190    #[test]
22191    fn recognition_arena_reports_live_dead_and_retained_capacity() {
22192        let mut arena = RecognitionArena::default();
22193        let token = arena.push_node(ArenaRecognizedNode::Token {
22194            token: TokenId::try_from(0).expect("test token ID"),
22195        });
22196        let extra = arena.push_extra(RecognitionExtra::MissingToken {
22197            token_type: 2,
22198            at_index: 1,
22199            text: "<missing X>".to_owned(),
22200        });
22201        let missing = arena.push_node(ArenaRecognizedNode::MissingToken { extra });
22202        let discarded = arena.push_node(ArenaRecognizedNode::ErrorToken {
22203            token: TokenId::try_from(1).expect("test token ID"),
22204        });
22205        let mut live = NodeSeqId::EMPTY;
22206        live = arena.prepend(live, missing);
22207        live = arena.prepend(live, token);
22208        let _discarded_sequence = arena.prepend(NodeSeqId::EMPTY, discarded);
22209        let live_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
22210            line: 1,
22211            column: 0,
22212            message: "missing X".to_owned(),
22213            offending: None,
22214        }]);
22215        let _discarded_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
22216            line: 1,
22217            column: 1,
22218            message: "discarded".to_owned(),
22219            offending: None,
22220        }]);
22221        let deferred_children = arena.deferred_fragment(live);
22222        let _deferred_rule = arena.deferred_rule_node(FastDeferredRule {
22223            rule_index: 0,
22224            invoking_state: -1,
22225            start_index: 0,
22226            stop_index: Some(1),
22227            deferred_children,
22228            children: NodeSeqId::EMPTY,
22229        });
22230
22231        let stats = arena.stats(live, live_diagnostics);
22232
22233        assert_eq!(
22234            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
22235            (3, 2, 1)
22236        );
22237        assert_eq!(
22238            (stats.total_links, stats.live_links, stats.dead_links),
22239            (5, 3, 2)
22240        );
22241        assert_eq!(
22242            (stats.total_extras, stats.live_extras, stats.dead_extras),
22243            (3, 2, 1)
22244        );
22245        assert!(size_of::<SeqLink>() <= 8);
22246        assert!(size_of::<DiagnosticLink>() <= 8);
22247        assert!(size_of::<FastDeferredNode>() <= 12);
22248        assert!(size_of::<FastDeferredRule>() <= 28);
22249        assert!(size_of::<FastRecognizeOutcome>() <= 24);
22250        let capacities = (
22251            stats.node_capacity,
22252            stats.link_capacity,
22253            stats.extra_capacity,
22254        );
22255        let deferred_capacities = (
22256            arena.deferred_nodes.capacity(),
22257            arena.deferred_rules.capacity(),
22258        );
22259
22260        arena.reset();
22261        let reset = arena.stats(NodeSeqId::EMPTY, DiagnosticSeqId::EMPTY);
22262        assert_eq!(
22263            (reset.total_nodes, reset.total_links, reset.total_extras),
22264            (0, 0, 0)
22265        );
22266        assert_eq!(
22267            (
22268                reset.node_capacity,
22269                reset.link_capacity,
22270                reset.extra_capacity,
22271            ),
22272            capacities
22273        );
22274        assert!(arena.deferred_nodes.is_empty());
22275        assert!(arena.deferred_rules.is_empty());
22276        assert_eq!(
22277            (
22278                arena.deferred_nodes.capacity(),
22279                arena.deferred_rules.capacity(),
22280            ),
22281            deferred_capacities
22282        );
22283    }
22284
22285    #[test]
22286    fn parser_computes_recognition_arena_stats_on_demand() {
22287        let mut parser = mini_parser(Vec::new());
22288        let live = parser
22289            .recognition_arena
22290            .push_node(ArenaRecognizedNode::Token {
22291                token: TokenId::try_from(0).expect("test token ID"),
22292            });
22293        let discarded = parser
22294            .recognition_arena
22295            .push_node(ArenaRecognizedNode::ErrorToken {
22296                token: TokenId::try_from(1).expect("test token ID"),
22297            });
22298        let live_root = parser.recognition_arena.prepend(NodeSeqId::EMPTY, live);
22299        let _discarded_root = parser
22300            .recognition_arena
22301            .prepend(NodeSeqId::EMPTY, discarded);
22302        parser.finish_recognition_arena(live_root, DiagnosticSeqId::EMPTY);
22303
22304        let stats = parser.recognition_arena_stats();
22305
22306        assert_eq!(
22307            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
22308            (2, 1, 1)
22309        );
22310        assert_eq!(
22311            (stats.total_links, stats.live_links, stats.dead_links),
22312            (2, 1, 1)
22313        );
22314    }
22315
22316    #[test]
22317    fn recognition_arena_drops_capacity_above_retention_limit() {
22318        let mut storage = Vec::<u8>::with_capacity(4);
22319        storage.extend([1, 2, 3]);
22320
22321        reset_arena_vec(&mut storage, 3);
22322
22323        assert!(storage.is_empty());
22324        assert_eq!(storage.capacity(), 0);
22325    }
22326
22327    #[test]
22328    fn recognition_arena_concatenates_diagnostics_in_source_order() {
22329        let mut arena = RecognitionArena::default();
22330        let prefix = arena.diagnostic_sequence([
22331            ParserDiagnostic {
22332                line: 1,
22333                column: 0,
22334                message: "first".to_owned(),
22335                offending: None,
22336            },
22337            ParserDiagnostic {
22338                line: 1,
22339                column: 1,
22340                message: "second".to_owned(),
22341                offending: None,
22342            },
22343        ]);
22344        let suffix = arena.diagnostic_sequence([ParserDiagnostic {
22345            line: 1,
22346            column: 2,
22347            message: "third".to_owned(),
22348            offending: None,
22349        }]);
22350        let extras_before = arena.extras.len();
22351
22352        let combined = arena.concat_diagnostics(prefix, suffix);
22353        let messages = arena
22354            .diagnostics(combined)
22355            .map(|diagnostic| diagnostic.message.as_str())
22356            .collect::<Vec<_>>();
22357
22358        assert_eq!(messages, ["first", "second", "third"]);
22359        assert_eq!(arena.extras.len(), extras_before);
22360    }
22361
22362    #[test]
22363    fn outcome_ties_keep_later_non_recursive_alternative() {
22364        let arena = RecognitionArena::default();
22365        let first = RecognizeOutcome {
22366            index: 1,
22367            consumed_eof: false,
22368            alt_number: 0,
22369            member_values: MemberEnv::new(),
22370            return_values: BTreeMap::new(),
22371            diagnostics: DiagnosticSeqId::EMPTY,
22372            decisions: Vec::new(),
22373            actions: vec![ParserAction::new(1, 0, 0, None)],
22374            nodes: NodeSeqId::EMPTY,
22375        };
22376        let second = RecognizeOutcome {
22377            actions: vec![ParserAction::new(2, 0, 0, None)],
22378            ..first.clone()
22379        };
22380
22381        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22382            .expect("one outcome should be selected");
22383        assert_eq!(selected.actions[0].source_state(), 2);
22384    }
22385
22386    #[test]
22387    fn outcome_ties_prefer_more_actions_for_non_recursive_paths() {
22388        let arena = RecognitionArena::default();
22389        let first = RecognizeOutcome {
22390            index: 1,
22391            consumed_eof: false,
22392            alt_number: 0,
22393            member_values: MemberEnv::new(),
22394            return_values: BTreeMap::new(),
22395            diagnostics: DiagnosticSeqId::EMPTY,
22396            decisions: Vec::new(),
22397            actions: vec![ParserAction::new(1, 0, 0, None)],
22398            nodes: NodeSeqId::EMPTY,
22399        };
22400        let second = RecognizeOutcome {
22401            actions: vec![
22402                ParserAction::new(2, 0, 0, None),
22403                ParserAction::new(3, 0, 0, None),
22404            ],
22405            ..first.clone()
22406        };
22407
22408        let selected = select_best_outcome([second, first].into_iter(), PredictionMode::Ll, &arena)
22409            .expect("one outcome should be selected");
22410        assert_eq!(selected.actions.len(), 2);
22411    }
22412
22413    #[test]
22414    fn outcome_ties_prefer_later_action_stop_for_greedy_optional_paths() {
22415        let arena = RecognitionArena::default();
22416        let first = RecognizeOutcome {
22417            index: 7,
22418            consumed_eof: false,
22419            alt_number: 0,
22420            member_values: MemberEnv::new(),
22421            return_values: BTreeMap::new(),
22422            diagnostics: DiagnosticSeqId::EMPTY,
22423            decisions: vec![1, 0],
22424            actions: vec![
22425                ParserAction::new(23, 2, 2, Some(4)),
22426                ParserAction::new(23, 2, 0, Some(6)),
22427            ],
22428            nodes: NodeSeqId::EMPTY,
22429        };
22430        let second = RecognizeOutcome {
22431            decisions: vec![0, 1],
22432            actions: vec![
22433                ParserAction::new(23, 2, 2, Some(6)),
22434                ParserAction::new(23, 2, 0, Some(6)),
22435            ],
22436            ..first.clone()
22437        };
22438
22439        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22440            .expect("one outcome should be selected");
22441        assert_eq!(selected.actions[0].stop_index(), Some(6));
22442    }
22443
22444    #[test]
22445    fn outcome_ties_keep_first_recursive_tree_shape() {
22446        let mut arena = RecognitionArena::default();
22447        let token = arena.push_node(ArenaRecognizedNode::Token {
22448            token: TokenId::try_from(0).expect("test token ID"),
22449        });
22450        let token_children = arena.prepend(NodeSeqId::EMPTY, token);
22451        let inner = arena.push_node(ArenaRecognizedNode::Rule {
22452            rule_index: 1,
22453            invoking_state: -1,
22454            alt_number: 0,
22455            start_index: 0,
22456            stop_index: Some(0),
22457            return_values: None,
22458            children: token_children,
22459        });
22460        let inner_children = arena.prepend(NodeSeqId::EMPTY, inner);
22461        let outer = arena.push_node(ArenaRecognizedNode::Rule {
22462            rule_index: 1,
22463            invoking_state: -1,
22464            alt_number: 0,
22465            start_index: 0,
22466            stop_index: Some(0),
22467            return_values: None,
22468            children: inner_children,
22469        });
22470        let recursive_nodes = arena.prepend(NodeSeqId::EMPTY, outer);
22471        let first = RecognizeOutcome {
22472            index: 1,
22473            consumed_eof: false,
22474            alt_number: 0,
22475            member_values: MemberEnv::new(),
22476            return_values: BTreeMap::new(),
22477            diagnostics: DiagnosticSeqId::EMPTY,
22478            decisions: Vec::new(),
22479            actions: vec![ParserAction::new(1, 0, 0, None)],
22480            nodes: recursive_nodes,
22481        };
22482        let second = RecognizeOutcome {
22483            index: 1,
22484            consumed_eof: false,
22485            alt_number: 0,
22486            member_values: MemberEnv::new(),
22487            return_values: BTreeMap::new(),
22488            diagnostics: DiagnosticSeqId::EMPTY,
22489            decisions: Vec::new(),
22490            actions: vec![ParserAction::new(2, 0, 0, None)],
22491            nodes: recursive_nodes,
22492        };
22493
22494        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22495            .expect("one outcome should be selected");
22496        assert_eq!(selected.actions[0].source_state(), 1);
22497    }
22498
22499    #[test]
22500    fn sll_outcome_selection_keeps_earlier_recovered_alt() {
22501        let mut arena = RecognitionArena::default();
22502        let recovered_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
22503            line: 1,
22504            column: 3,
22505            message: "missing 'Y' at '<EOF>'".to_owned(),
22506            offending: None,
22507        }]);
22508        let first_alt = RecognizeOutcome {
22509            index: 2,
22510            consumed_eof: true,
22511            alt_number: 0,
22512            member_values: MemberEnv::new(),
22513            return_values: BTreeMap::new(),
22514            diagnostics: recovered_diagnostics,
22515            decisions: vec![0],
22516            actions: vec![ParserAction::new(1, 0, 0, None)],
22517            nodes: NodeSeqId::EMPTY,
22518        };
22519        let second_alt = RecognizeOutcome {
22520            diagnostics: DiagnosticSeqId::EMPTY,
22521            decisions: vec![1],
22522            actions: vec![ParserAction::new(2, 0, 0, None)],
22523            ..first_alt.clone()
22524        };
22525
22526        let selected = select_best_outcome(
22527            [second_alt, first_alt].into_iter(),
22528            PredictionMode::Sll,
22529            &arena,
22530        )
22531        .expect("one outcome should be selected");
22532        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
22533        assert_eq!(selected.decisions, [0]);
22534    }
22535}