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        let Some(diagnostic) = &prediction.diagnostic else {
5655            return;
5656        };
5657        if !self.report_diagnostic_errors || diagnostic.conflicting_alts.len() < 2 {
5658            return;
5659        }
5660        let Some(decision) = atn
5661            .decision_to_state()
5662            .iter()
5663            .position(|candidate| candidate == state_number)
5664        else {
5665            return;
5666        };
5667        let Some(rule_index) = atn.state(state_number).and_then(AtnState::rule_index) else {
5668            return;
5669        };
5670        let rule_name = self
5671            .rule_names()
5672            .get(rule_index)
5673            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
5674        let attempt_input = display_input_text(
5675            &self
5676                .input
5677                .text(diagnostic.start_index, diagnostic.sll_stop_index),
5678        );
5679        let result_input = display_input_text(
5680            &self
5681                .input
5682                .text(diagnostic.start_index, diagnostic.ll_stop_index),
5683        );
5684        let alts = diagnostic
5685            .conflicting_alts
5686            .iter()
5687            .map(usize::to_string)
5688            .collect::<Vec<_>>()
5689            .join(", ");
5690        let key = (
5691            decision,
5692            diagnostic.start_index,
5693            format!(
5694                "{:?}:{alts}:{attempt_input}:{result_input}",
5695                diagnostic.kind
5696            ),
5697        );
5698        if !self.reported_prediction_diagnostics.insert(key) {
5699            return;
5700        }
5701        let attempt_diagnostic = diagnostic_for_token(
5702            self.token_at(diagnostic.sll_stop_index),
5703            format!(
5704                "reportAttemptingFullContext d={decision} ({rule_name}), input='{attempt_input}'"
5705            ),
5706        );
5707        self.generated_parser_diagnostics.push(attempt_diagnostic);
5708        let message = match diagnostic.kind {
5709            ParserAtnPredictionDiagnosticKind::Ambiguity => {
5710                // Java's DiagnosticErrorListener is exactOnly by default:
5711                // non-exact ambiguities (default LL mode stopping at the
5712                // first resolvable conflict) report the attempt above but
5713                // suppress the ambiguity line itself.
5714                if !diagnostic.exact {
5715                    return;
5716                }
5717                format!(
5718                    "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{result_input}'"
5719                )
5720            }
5721            ParserAtnPredictionDiagnosticKind::ContextSensitivity => {
5722                format!(
5723                    "reportContextSensitivity d={decision} ({rule_name}), input='{result_input}'"
5724                )
5725            }
5726        };
5727        let result_diagnostic =
5728            diagnostic_for_token(self.token_at(diagnostic.ll_stop_index), message);
5729        self.generated_parser_diagnostics.push(result_diagnostic);
5730    }
5731
5732    pub fn la(&self, offset: isize) -> i32 {
5733        self.input.la_token(offset)
5734    }
5735
5736    pub fn consume(&mut self) {
5737        IntStream::consume(&mut self.input);
5738    }
5739
5740    /// Sets a generated integer member value used by target-template tests.
5741    pub fn set_int_member(&mut self, member: usize, value: i64) {
5742        self.int_members.set_scalar(member, value);
5743    }
5744
5745    /// Reads a generated integer member value.
5746    pub fn int_member(&self, member: usize) -> Option<i64> {
5747        self.int_members.scalar(member)
5748    }
5749
5750    /// Pushes onto a generated stack-valued member slot (issue #206).
5751    pub fn push_stack_member(&mut self, member: usize, value: i64) {
5752        self.int_members.push_stack(member, value);
5753    }
5754
5755    /// Pops a generated stack-valued member slot, returning the removed value.
5756    /// `None` when the stack is empty.
5757    pub fn pop_stack_member(&mut self, member: usize) -> Option<i64> {
5758        self.int_members.pop_stack(member)
5759    }
5760
5761    /// Reads the top of a generated stack-valued member slot; `None` when
5762    /// empty or never pushed.
5763    #[must_use]
5764    pub fn stack_member_top(&self, member: usize) -> Option<i64> {
5765        self.int_members.stack_top(member)
5766    }
5767
5768    /// Depth of a generated stack-valued member slot.
5769    #[must_use]
5770    pub fn stack_member_len(&self, member: usize) -> usize {
5771        self.int_members.stack_len(member)
5772    }
5773
5774    /// Seeds grammar-declared initial member values (issue #206).
5775    ///
5776    /// Generated parsers call this at construction for a grammar whose
5777    /// `@members` declares an initializer (`private int level = 1;`). Without
5778    /// it the slot would start at 0, so a predicate reading it would reject
5779    /// input the source grammar accepts.
5780    pub fn set_initial_members(&mut self, initial: impl IntoIterator<Item = (usize, i64)>) {
5781        self.int_members = MemberEnv::with_initial_scalars(initial);
5782    }
5783
5784    /// Captures generated member state before speculative generated parser
5785    /// execution.
5786    ///
5787    /// The snapshot covers scalar *and* stack slots: restoring only scalars
5788    /// would leave a rolled-back path's pushes behind.
5789    #[must_use]
5790    pub fn int_members_checkpoint(&self) -> MemberEnv {
5791        self.int_members.clone()
5792    }
5793
5794    /// Restores generated member state after generated parser fallback.
5795    pub fn restore_int_members(&mut self, members: MemberEnv) {
5796        self.int_members = members;
5797    }
5798
5799    /// Adds `delta` to a generated integer member and returns the new value.
5800    pub fn add_int_member(&mut self, member: usize, delta: i64) -> i64 {
5801        self.int_members.add_scalar(member, delta)
5802    }
5803
5804    fn token_type_for_id(&self, id: TokenId) -> i32 {
5805        self.input.token_store().token_type(id).unwrap_or(TOKEN_EOF)
5806    }
5807
5808    fn terminal_tree(&mut self, id: TokenId) -> ParseTree {
5809        if self.build_parse_trees {
5810            self.tree.terminal(id)
5811        } else {
5812            NodeId::placeholder()
5813        }
5814    }
5815
5816    fn error_tree(&mut self, id: TokenId) -> ParseTree {
5817        if self.build_parse_trees {
5818            self.tree.error(id)
5819        } else {
5820            NodeId::placeholder()
5821        }
5822    }
5823
5824    const fn set_context_start(&self, context: &mut ParserRuleContext, id: TokenId) {
5825        context.set_start_id(id);
5826    }
5827
5828    const fn set_context_stop(&self, context: &mut ParserRuleContext, id: TokenId) {
5829        context.set_stop_id(id);
5830    }
5831
5832    fn insert_synthetic_token(
5833        &mut self,
5834        token_type: i32,
5835        text: String,
5836        line: usize,
5837        column: usize,
5838    ) -> Result<TokenId, AntlrError> {
5839        self.input
5840            .insert(
5841                TokenSpec::explicit(token_type, text)
5842                    .with_span(usize::MAX, usize::MAX)
5843                    .with_position(line, column),
5844            )
5845            .map_err(|error| AntlrError::Unsupported(error.to_string()))
5846    }
5847
5848    /// Matches and consumes the current token when it has the expected token
5849    /// type.
5850    ///
5851    /// On success the consumed token is wrapped as a terminal parse-tree node.
5852    /// On mismatch the error carries vocabulary display names so diagnostics are
5853    /// stable across literal and symbolic token naming.
5854    pub fn match_token(&mut self, token_type: i32) -> Result<ParseTree, AntlrError> {
5855        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5856            line: 0,
5857            column: 0,
5858            message: "missing current token".to_owned(),
5859            offending: None,
5860        })?;
5861        let current_type = self.token_type_for_id(current);
5862        if current_type == token_type {
5863            self.reset_generated_recovery_state();
5864            self.consume();
5865            Ok(self.terminal_tree(current))
5866        } else {
5867            Err(AntlrError::MismatchedInput {
5868                expected: self.vocabulary().display_name(token_type),
5869                found: self.vocabulary().display_name(current_type),
5870            })
5871        }
5872    }
5873
5874    /// Matches a token from generated recursive-descent code, including ANTLR's
5875    /// single-token insertion recovery when the active rule context can legally
5876    /// continue at the current input symbol.
5877    pub fn match_token_recovering(
5878        &mut self,
5879        token_type: i32,
5880        follow_state: usize,
5881        atn: &Atn,
5882    ) -> Result<GeneratedMatch, AntlrError> {
5883        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5884            line: 0,
5885            column: 0,
5886            message: "missing current token".to_owned(),
5887            offending: None,
5888        })?;
5889        let current_type = self.token_type_for_id(current);
5890        if current_type == token_type {
5891            self.generated_sync_expected = None;
5892            self.reset_generated_recovery_state();
5893            let consumed_eof = current_type == TOKEN_EOF;
5894            self.consume();
5895            return Ok(GeneratedMatch {
5896                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5897                consumed_eof,
5898            });
5899        }
5900        let mut expected_symbols = BTreeSet::new();
5901        expected_symbols.insert(token_type);
5902        self.recover_generated_match(
5903            current,
5904            GeneratedExpectedSymbols::Tree(&expected_symbols),
5905            follow_state,
5906            atn,
5907            |symbol| symbol == token_type,
5908        )
5909    }
5910
5911    pub fn match_set_recovering(
5912        &mut self,
5913        intervals: &[(i32, i32)],
5914        follow_state: usize,
5915        atn: &Atn,
5916    ) -> Result<GeneratedMatch, AntlrError> {
5917        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5918            line: 0,
5919            column: 0,
5920            message: "missing current token".to_owned(),
5921            offending: None,
5922        })?;
5923        let current_type = self.token_type_for_id(current);
5924        if interval_set_contains(intervals, current_type) {
5925            self.generated_sync_expected = None;
5926            self.reset_generated_recovery_state();
5927            let consumed_eof = current_type == TOKEN_EOF;
5928            self.consume();
5929            return Ok(GeneratedMatch {
5930                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5931                consumed_eof,
5932            });
5933        }
5934        let expected_symbols = interval_symbols(intervals);
5935        self.recover_generated_match(
5936            current,
5937            GeneratedExpectedSymbols::Tree(&expected_symbols),
5938            follow_state,
5939            atn,
5940            |symbol| interval_set_contains(intervals, symbol),
5941        )
5942    }
5943
5944    pub fn match_token_set_recovering(
5945        &mut self,
5946        set: ParserIntervalSet<'_>,
5947        follow_state: usize,
5948        atn: &Atn,
5949    ) -> Result<GeneratedMatch, AntlrError> {
5950        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5951            line: 0,
5952            column: 0,
5953            message: "missing current token".to_owned(),
5954            offending: None,
5955        })?;
5956        let current_type = self.token_type_for_id(current);
5957        if set.contains(current_type) {
5958            self.generated_sync_expected = None;
5959            self.reset_generated_recovery_state();
5960            let consumed_eof = current_type == TOKEN_EOF;
5961            self.consume();
5962            return Ok(GeneratedMatch {
5963                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
5964                consumed_eof,
5965            });
5966        }
5967        self.recover_generated_match(
5968            current,
5969            GeneratedExpectedSymbols::TokenSet(set),
5970            follow_state,
5971            atn,
5972            |symbol| set.contains(symbol),
5973        )
5974    }
5975
5976    pub fn match_not_set_recovering(
5977        &mut self,
5978        intervals: &[(i32, i32)],
5979        min_vocabulary: i32,
5980        max_vocabulary: i32,
5981        follow_state: usize,
5982        atn: &Atn,
5983    ) -> Result<GeneratedMatch, AntlrError> {
5984        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
5985            line: 0,
5986            column: 0,
5987            message: "missing current token".to_owned(),
5988            offending: None,
5989        })?;
5990        let current_type = self.token_type_for_id(current);
5991        if (min_vocabulary..=max_vocabulary).contains(&current_type)
5992            && !interval_set_contains(intervals, current_type)
5993        {
5994            self.generated_sync_expected = None;
5995            self.reset_generated_recovery_state();
5996            let consumed_eof = current_type == TOKEN_EOF;
5997            self.consume();
5998            return Ok(GeneratedMatch {
5999                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
6000                consumed_eof,
6001            });
6002        }
6003        let expected_symbols =
6004            interval_complement_symbols(intervals, min_vocabulary, max_vocabulary);
6005        self.recover_generated_match(
6006            current,
6007            GeneratedExpectedSymbols::Tree(&expected_symbols),
6008            follow_state,
6009            atn,
6010            |symbol| {
6011                (min_vocabulary..=max_vocabulary).contains(&symbol)
6012                    && !interval_set_contains(intervals, symbol)
6013            },
6014        )
6015    }
6016
6017    pub fn match_not_token_set_recovering(
6018        &mut self,
6019        set: ParserIntervalSet<'_>,
6020        min_vocabulary: i32,
6021        max_vocabulary: i32,
6022        follow_state: usize,
6023        atn: &Atn,
6024    ) -> Result<GeneratedMatch, AntlrError> {
6025        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6026            line: 0,
6027            column: 0,
6028            message: "missing current token".to_owned(),
6029            offending: None,
6030        })?;
6031        let current_type = self.token_type_for_id(current);
6032        if (min_vocabulary..=max_vocabulary).contains(&current_type) && !set.contains(current_type)
6033        {
6034            self.generated_sync_expected = None;
6035            self.reset_generated_recovery_state();
6036            let consumed_eof = current_type == TOKEN_EOF;
6037            self.consume();
6038            return Ok(GeneratedMatch {
6039                children: GeneratedMatchChildren::One(self.terminal_tree(current)),
6040                consumed_eof,
6041            });
6042        }
6043        self.recover_generated_match(
6044            current,
6045            GeneratedExpectedSymbols::TokenSetComplement {
6046                set,
6047                min_vocabulary,
6048                max_vocabulary,
6049            },
6050            follow_state,
6051            atn,
6052            |symbol| (min_vocabulary..=max_vocabulary).contains(&symbol) && !set.contains(symbol),
6053        )
6054    }
6055
6056    fn recover_generated_match(
6057        &mut self,
6058        current: TokenId,
6059        expected_symbols: GeneratedExpectedSymbols<'_>,
6060        follow_state: usize,
6061        atn: &Atn,
6062        matches: impl Fn(i32) -> bool,
6063    ) -> Result<GeneratedMatch, AntlrError> {
6064        let expected_display = expected_symbols.display(self.vocabulary());
6065        let (current_type, current_line, current_column, current_display) = {
6066            let token = self
6067                .input
6068                .token_view(current)
6069                .expect("current token ID should be valid");
6070            (
6071                token.token_type(),
6072                token.line(),
6073                token.column(),
6074                token_input_display(&token),
6075            )
6076        };
6077        if self.bail_on_error {
6078            return Err(AntlrError::ParserError {
6079                line: current_line,
6080                column: current_column,
6081                message: format!("mismatched input {current_display} expecting {expected_display}"),
6082                offending: Some(current),
6083            });
6084        }
6085        if current_type != TOKEN_EOF
6086            && let Some(next) = self.input.lt_id(2)
6087            && matches(self.token_type_for_id(next))
6088        {
6089            let message =
6090                format!("extraneous input {current_display} expecting {expected_display}");
6091            self.push_generated_parser_diagnostic(ParserDiagnostic {
6092                line: current_line,
6093                column: current_column,
6094                message,
6095                offending: Some(current),
6096            });
6097            self.record_syntax_errors(1);
6098            self.generated_sync_expected = None;
6099            // Single-token deletion: skip `current`, then accept `next`. The
6100            // accepted token can be EOF only if it is a real EOF terminal.
6101            let consumed_eof = self.token_type_for_id(next) == TOKEN_EOF;
6102            self.consume();
6103            self.consume();
6104            self.reset_generated_recovery_state();
6105            return Ok(GeneratedMatch {
6106                children: GeneratedMatchChildren::Many(vec![
6107                    self.error_tree(current),
6108                    self.terminal_tree(next),
6109                ]),
6110                consumed_eof,
6111            });
6112        }
6113        let follow_symbols = self.generated_recovery_follow_symbols(atn, follow_state);
6114        // ANTLR's `singleTokenInsertion` inserts a missing token when the state
6115        // *after* the current element can consume the current symbol. At EOF that
6116        // only holds when the follow state EXPLICITLY expects EOF (e.g. an `EOF`
6117        // terminal follows in the rule, as in `r: . EOF;` or `r: ID EOF;`), not
6118        // when EOF merely leaks in from the empty enclosing context (as in
6119        // `start: ID+;` on empty input — antlr#6 `InvalidEmptyInput`, which must
6120        // stay a `mismatched input` error). `follow_symbols` mixes both sources,
6121        // so consult the follow state's OWN expected set for the explicit case.
6122        let follow_explicitly_expects_eof = current_type == TOKEN_EOF
6123            && self
6124                .cached_state_expected_symbols(atn, follow_state)
6125                .contains(&TOKEN_EOF);
6126        if follow_symbols.contains(&current_type)
6127            && (current_type != TOKEN_EOF
6128                || self.rule_context_stack.len() > 1
6129                || expected_symbols.is_empty()
6130                || follow_explicitly_expects_eof)
6131        {
6132            let message = format!("missing {expected_display} at {current_display}");
6133            self.push_generated_parser_diagnostic(ParserDiagnostic {
6134                line: current_line,
6135                column: current_column,
6136                message,
6137                offending: Some(current),
6138            });
6139            self.record_syntax_errors(1);
6140            self.generated_sync_expected = None;
6141            let token_type = expected_symbols.first().unwrap_or(TOKEN_EOF);
6142            let missing_display = expected_symbol_display(token_type, self.vocabulary());
6143            let token = self.insert_synthetic_token(
6144                token_type,
6145                format!("<missing {missing_display}>"),
6146                current_line,
6147                current_column,
6148            )?;
6149            // Single-token insertion synthesizes a missing token and consumes
6150            // nothing, so no EOF terminal is consumed even when the lookahead is
6151            // EOF. Reporting consumed_eof=false here is what keeps `finish_rule`
6152            // from recording EOF as the rule stop on this recovery path.
6153            return Ok(GeneratedMatch {
6154                children: GeneratedMatchChildren::One(self.error_tree(token)),
6155                consumed_eof: false,
6156            });
6157        }
6158        let mismatch_expected_display = self
6159            .generated_sync_expected
6160            .take()
6161            .map_or(expected_display, |symbols| {
6162                expected_symbols_display_iter(symbols.symbols(), self.vocabulary())
6163            });
6164        Err(AntlrError::ParserError {
6165            line: current_line,
6166            column: current_column,
6167            message: format!(
6168                "mismatched input {current_display} expecting {mismatch_expected_display}"
6169            ),
6170            offending: Some(current),
6171        })
6172    }
6173
6174    fn generated_recovery_follow_symbols(
6175        &mut self,
6176        atn: &Atn,
6177        follow_state: usize,
6178    ) -> BTreeSet<i32> {
6179        let mut follow = self
6180            .cached_state_expected_symbols(atn, follow_state)
6181            .as_ref()
6182            .clone();
6183        if self.cached_state_can_reach_rule_stop(atn, follow_state) {
6184            follow.extend(self.context_expected_symbols(atn));
6185        }
6186        follow
6187    }
6188
6189    pub fn match_eof(&mut self) -> Result<ParseTree, AntlrError> {
6190        self.match_token(TOKEN_EOF)
6191    }
6192
6193    pub fn match_set(&mut self, intervals: &[(i32, i32)]) -> Result<ParseTree, AntlrError> {
6194        self.match_interval_condition(intervals, |symbol| interval_set_contains(intervals, symbol))
6195    }
6196
6197    pub fn match_not_set(
6198        &mut self,
6199        intervals: &[(i32, i32)],
6200        min_vocabulary: i32,
6201        max_vocabulary: i32,
6202    ) -> Result<ParseTree, AntlrError> {
6203        self.match_interval_condition(intervals, |symbol| {
6204            (min_vocabulary..=max_vocabulary).contains(&symbol)
6205                && !interval_set_contains(intervals, symbol)
6206        })
6207    }
6208
6209    fn match_interval_condition(
6210        &mut self,
6211        intervals: &[(i32, i32)],
6212        matches: impl FnOnce(i32) -> bool,
6213    ) -> Result<ParseTree, AntlrError> {
6214        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
6215            line: 0,
6216            column: 0,
6217            message: "missing current token".to_owned(),
6218            offending: None,
6219        })?;
6220        let current_type = self.token_type_for_id(current);
6221        if matches(current_type) {
6222            self.reset_generated_recovery_state();
6223            self.consume();
6224            Ok(self.terminal_tree(current))
6225        } else {
6226            Err(AntlrError::MismatchedInput {
6227                expected: self.interval_display(intervals),
6228                found: self.vocabulary().display_name(current_type),
6229            })
6230        }
6231    }
6232
6233    fn interval_display(&self, intervals: &[(i32, i32)]) -> String {
6234        let values = intervals
6235            .iter()
6236            .map(|(start, stop)| {
6237                if start == stop {
6238                    self.vocabulary().display_name(*start)
6239                } else {
6240                    format!(
6241                        "{}..{}",
6242                        self.vocabulary().display_name(*start),
6243                        self.vocabulary().display_name(*stop)
6244                    )
6245                }
6246            })
6247            .collect::<Vec<_>>()
6248            .join(", ");
6249        format!("{{{values}}}")
6250    }
6251
6252    pub fn rule_node(&mut self, context: ParserRuleContext) -> ParseTree {
6253        if self.build_parse_trees {
6254            self.tree.finish_rule(context)
6255        } else {
6256            NodeId::placeholder()
6257        }
6258    }
6259
6260    /// Reports whether the generated rule dispatch should sample native stack
6261    /// capacity before descending into the next rule body.
6262    ///
6263    /// Generated recursive-descent methods otherwise map unbounded grammar
6264    /// nesting straight onto native call depth; sampling every
6265    /// [`GENERATED_RULE_STACK_CHECK_INTERVAL`] rule-context frames keeps the
6266    /// hot path free of per-call probes while guaranteeing a check runs before
6267    /// the red zone can be crossed.
6268    #[must_use]
6269    pub const fn generated_rule_stack_check_due(&self) -> bool {
6270        self.rule_context_stack
6271            .len()
6272            .is_multiple_of(GENERATED_RULE_STACK_CHECK_INTERVAL)
6273    }
6274
6275    /// Returns the positioned error to abort with when the configured
6276    /// rule-nesting depth cap would be exceeded by one more level, or `None`
6277    /// to keep parsing.
6278    ///
6279    /// Generated rule dispatch calls this before deepening — ahead of the
6280    /// rule-frame push at the dispatch boundary and ahead of each
6281    /// left-recursive expansion — letting callers parsing untrusted input
6282    /// bound CPU and tree memory ([`Parser::set_max_rule_depth`]). The
6283    /// inline fast path is one `Option` check when no cap is set (the
6284    /// default) and one addition plus compare when one is; only an actual
6285    /// violation leaves the inline path.
6286    ///
6287    /// The violation is sticky: rule-level recovery absorbs the returned
6288    /// error like any other rule failure and would otherwise keep spending
6289    /// the very resources the cap exists to bound, so every check after the
6290    /// first violation fails until [`Self::take_rule_depth_error`] drains it
6291    /// at the top-level entry.
6292    #[inline]
6293    pub fn rule_depth_cap_violation(&mut self) -> Option<AntlrError> {
6294        let max = self.max_rule_depth?;
6295        // Left-recursive operator iterations deepen the tree without pushing
6296        // a rule frame, so they count alongside the rule-context stack.
6297        if self.rule_depth_error.is_none()
6298            && self.rule_context_stack.len() + self.recursion_expansions < max
6299        {
6300            return None;
6301        }
6302        Some(self.rule_depth_cap_violation_cold(max))
6303    }
6304
6305    #[cold]
6306    fn rule_depth_cap_violation_cold(&mut self, max: usize) -> AntlrError {
6307        if let Some(error) = &self.rule_depth_error {
6308            return error.clone();
6309        }
6310        let current = self.input.lt(1);
6311        let (line, column) = current
6312            .as_ref()
6313            .map_or((0, 0), |token| (token.line(), token.column()));
6314        let error = AntlrError::ParserError {
6315            line,
6316            column,
6317            message: format!("rule nesting depth limit of {max} exceeded"),
6318            offending: current.as_ref().map(Token::token_id),
6319        };
6320        self.rule_depth_error = Some(error.clone());
6321        error
6322    }
6323
6324    /// Drains the sticky depth-cap violation recorded by
6325    /// [`Self::rule_depth_cap_violation`], if any.
6326    ///
6327    /// Generated top-level rule entries call this after recognition so a
6328    /// recovered parse that crossed the cap still fails, and so a reused
6329    /// parser starts its next parse clean.
6330    pub const fn take_rule_depth_error(&mut self) -> Option<AntlrError> {
6331        self.rule_depth_error.take()
6332    }
6333
6334    /// Reports whether a rule-nesting depth cap is configured.
6335    ///
6336    /// Generated dispatch consults this when selecting between the guarded
6337    /// recursive-descent body and the ATN-preferred interpreted fast path:
6338    /// only the generated body enforces the cap, so a configured bound
6339    /// overrides the performance preference.
6340    #[must_use]
6341    pub const fn has_rule_depth_cap(&self) -> bool {
6342        self.max_rule_depth.is_some()
6343    }
6344
6345    /// Registers a listener for committed rule enter/exit events during
6346    /// recognition (ANTLR's `addParseListener`). See [`ParseListener`] for
6347    /// the delivery contract.
6348    pub fn add_parse_listener<L>(&mut self, listener: L)
6349    where
6350        L: ParseListener + 'static,
6351    {
6352        self.parse_listeners
6353            .push(ParseListenerSlot(Box::new(listener)));
6354    }
6355
6356    /// Removes every registered parse listener and returns them, dropping any
6357    /// sticky abort a removed listener had requested.
6358    ///
6359    /// Returning the boxed listeners gives callers back the state they
6360    /// accumulated (depth counters, collected events) without threading
6361    /// shared handles through the listener.
6362    pub fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
6363        self.parse_listener_abort = None;
6364        self.parse_listeners.drain(..).map(|slot| slot.0).collect()
6365    }
6366
6367    /// Reports whether any parse listener is registered.
6368    ///
6369    /// Generated dispatch consults this alongside [`Self::has_rule_depth_cap`]
6370    /// when choosing between the generated body (which fires events) and the
6371    /// ATN-preferred interpreted fast path (which does not).
6372    #[must_use]
6373    pub const fn has_parse_listeners(&self) -> bool {
6374        !self.parse_listeners.is_empty()
6375    }
6376
6377    /// Reports whether semantic hooks may override interpreted decisions.
6378    ///
6379    /// Generated parsers use this to keep adaptive performance routing from
6380    /// changing parse semantics after a decision DFA becomes warm.
6381    #[doc(hidden)]
6382    #[must_use]
6383    pub fn observes_parser_decisions(&self) -> bool {
6384        self.semantic_hooks.observes_parser_decisions()
6385    }
6386
6387    /// Fires `enter_every_rule` on registered parse listeners, returning the
6388    /// abort error if any listener requested one.
6389    ///
6390    /// Generated rule dispatch calls this after the depth-cap probe and
6391    /// before the rule body runs; the generated left-recursive loop calls it
6392    /// once per operator expansion, mirroring upstream ANTLR's simulated
6393    /// rule-entry event for `pushNewRecursionContext`. A listener abort is
6394    /// sticky exactly like a depth-cap violation: rule-level recovery absorbs
6395    /// the returned error, so the flag holds until the top-level entry drains
6396    /// it via [`Self::take_parse_listener_abort`] and fails the parse.
6397    pub fn parse_listener_enter_rule(&mut self, rule_index: usize) -> Option<AntlrError> {
6398        if self.parse_listeners.is_empty() {
6399            return None;
6400        }
6401        self.parse_listener_enter_rule_dispatch(rule_index)
6402    }
6403
6404    fn parse_listener_enter_rule_dispatch(&mut self, rule_index: usize) -> Option<AntlrError> {
6405        if let Some(error) = &self.parse_listener_abort {
6406            return Some(error.clone());
6407        }
6408        let event = EnterRuleEvent {
6409            rule_index,
6410            current: self.input.lt(1),
6411        };
6412        // Split borrows: the token view borrows the input while listeners
6413        // need `&mut`, so listeners are taken out for the dispatch. Listener
6414        // methods have no parser access and cannot observe the absence.
6415        let mut listeners = std::mem::take(&mut self.parse_listeners);
6416        let mut abort = None;
6417        for slot in &mut listeners {
6418            if let Err(error) = slot.0.enter_every_rule(&event) {
6419                abort = Some(error);
6420                break;
6421            }
6422        }
6423        self.parse_listeners = listeners;
6424        if let Some(error) = abort {
6425            self.parse_listener_abort = Some(error.clone());
6426            return Some(error);
6427        }
6428        None
6429    }
6430
6431    /// Fires `exit_every_rule` on registered parse listeners.
6432    ///
6433    /// Generated rule bodies call this on every exit path — success and
6434    /// recovery alike — keeping enter/exit pairs balanced, and the generated
6435    /// left-recursive loop calls it once per operator expansion when the rule
6436    /// finishes unrolling.
6437    pub fn parse_listener_exit_rule(&mut self, rule_index: usize) {
6438        if self.parse_listeners.is_empty() {
6439            return;
6440        }
6441        // Reverse registration order, matching upstream ANTLR
6442        // (`Parser.triggerExitRuleEvent` walks listeners back to front).
6443        for slot in self.parse_listeners.iter_mut().rev() {
6444            slot.0.exit_every_rule(rule_index);
6445        }
6446    }
6447
6448    /// Drains the sticky parse-listener abort recorded by
6449    /// [`Self::parse_listener_enter_rule`], if any.
6450    ///
6451    /// Generated top-level rule entries call this after recognition so an
6452    /// aborted parse fails even when recovery produced a tree, and so a
6453    /// reused parser starts its next parse clean.
6454    pub const fn take_parse_listener_abort(&mut self) -> Option<AntlrError> {
6455        self.parse_listener_abort.take()
6456    }
6457
6458    /// Drains every sticky parse abort — the depth-cap violation and the
6459    /// parse-listener abort — returning the depth error preferentially.
6460    ///
6461    /// Generated top-level rule entries call this on both exit paths: the
6462    /// recorded abort wins over errors derived from it (recovery may have
6463    /// absorbed the aborted rule and failed differently later), a recovered
6464    /// `Ok` tree still fails when an abort was recorded, and draining leaves
6465    /// the instance clean for the next entry-rule call.
6466    pub fn take_parse_abort(&mut self) -> Option<AntlrError> {
6467        if let Some(error) = self.rule_depth_error.take() {
6468            self.parse_listener_abort = None;
6469            return Some(error);
6470        }
6471        self.parse_listener_abort.take()
6472    }
6473
6474    /// Enters a generated parser rule and returns the context object the
6475    /// generated method should populate.
6476    pub fn enter_rule(&mut self, state: isize, rule_index: usize) -> ParserRuleContext {
6477        self.set_state(state);
6478        let invoking_state = self.pending_invoking_states.pop().unwrap_or(state);
6479        self.rule_context_stack.push(RuleContextFrame {
6480            rule_index,
6481            invoking_state,
6482        });
6483        self.advance_rule_context_version();
6484        let start_index = self.current_visible_index();
6485        let mut context = ParserRuleContext::new(rule_index, invoking_state);
6486        if let Some(token) = self.token_id_at(start_index) {
6487            self.set_context_start(&mut context, token);
6488        }
6489        context
6490    }
6491
6492    /// Records the ATN source state for the next generated rule invocation.
6493    ///
6494    /// ANTLR's full-context prediction reconstructs caller follow states from
6495    /// each active rule context's invoking state. Generated Rust rule methods are
6496    /// plain functions, so the caller supplies that ATN state just before making a
6497    /// rule call; `enter_rule` consumes it when the callee starts.
6498    pub fn push_invoking_state(&mut self, invoking_state: isize) -> usize {
6499        let marker = self.pending_invoking_states.len();
6500        self.pending_invoking_states.push(invoking_state);
6501        marker
6502    }
6503
6504    /// Discards an invoking-state marker if the callee did not consume it.
6505    pub fn discard_invoking_state(&mut self, marker: usize) {
6506        self.pending_invoking_states.truncate(marker);
6507    }
6508
6509    /// Exits the current generated parser rule.
6510    pub fn exit_rule(&mut self) {
6511        self.rule_context_stack.pop();
6512        self.advance_rule_context_version();
6513    }
6514
6515    /// Returns caller follow states for interning in a parser ATN simulator's
6516    /// prediction store. States are yielded outermost to innermost.
6517    pub fn prediction_context_return_states<'a>(
6518        &'a self,
6519        atn: &'a Atn,
6520    ) -> impl DoubleEndedIterator<Item = usize> + 'a {
6521        self.rule_context_stack.iter().skip(1).filter_map(|frame| {
6522            let Ok(state_number) = usize::try_from(frame.invoking_state) else {
6523                return None;
6524            };
6525            let Some(Transition::Rule { follow_state, .. }) = atn
6526                .state(state_number)
6527                .and_then(|state| state.transitions().first())
6528                .map(ParserTransition::data)
6529            else {
6530                return None;
6531            };
6532            Some(follow_state)
6533        })
6534    }
6535
6536    /// Returns a generation that changes whenever the active rule stack changes.
6537    ///
6538    /// A parser ATN simulator uses this to reuse an interned outer prediction
6539    /// context while generated predictions remain in the same rule context.
6540    pub const fn rule_context_version(&self) -> usize {
6541        self.rule_context_version
6542    }
6543
6544    const fn advance_rule_context_version(&mut self) {
6545        self.rule_context_version = self.rule_context_version.wrapping_add(1);
6546    }
6547
6548    /// Adds a generated parser child only when parse-tree construction is
6549    /// enabled. The match is recorded on the context either way (via `add_child`,
6550    /// or `note_matched_child` when trees are off) so generated recovery can tell
6551    /// whether the rule has matched anything yet without depending on `children`.
6552    pub fn add_parse_child(&mut self, context: &mut ParserRuleContext, child: ParseTree) {
6553        if self.build_parse_trees {
6554            self.tree.add_child(context, child);
6555        } else {
6556            context.note_matched_child();
6557        }
6558    }
6559
6560    /// Combined sync-decision + child-append + sync-error capture.
6561    ///
6562    /// Replaces the 9-line generated sync-decision motif with a single call.
6563    /// On success, appends any sync children to the context. On error, stores
6564    /// the error in `sync_error` and returns `Err` for the caller to propagate.
6565    #[inline]
6566    pub fn sync_into(
6567        &mut self,
6568        atn: &Atn,
6569        state_number: usize,
6570        context: &mut ParserRuleContext,
6571        loop_back: bool,
6572        sync_error: &mut Option<AntlrError>,
6573    ) -> Result<(), AntlrError> {
6574        let current_context_empty = !context.has_matched_child();
6575        match self.sync_decision(atn, state_number, current_context_empty, loop_back) {
6576            Ok(children) => {
6577                for child in children {
6578                    self.add_parse_child(context, child);
6579                }
6580                Ok(())
6581            }
6582            Err(error) => {
6583                *sync_error = Some(error.clone());
6584                Err(error)
6585            }
6586        }
6587    }
6588
6589    /// Combined token-match + EOF accounting + child append.
6590    ///
6591    /// Replaces the 3-line generated token-match motif with a single call.
6592    #[inline]
6593    pub fn match_token_into(
6594        &mut self,
6595        token_type: i32,
6596        follow_state: usize,
6597        atn: &Atn,
6598        context: &mut ParserRuleContext,
6599        consumed_eof: &mut bool,
6600    ) -> Result<(), AntlrError> {
6601        let m = self.match_token_recovering(token_type, follow_state, atn)?;
6602        *consumed_eof |= m.consumed_eof();
6603        for child in m.into_child_iter() {
6604            self.add_parse_child(context, child);
6605        }
6606        Ok(())
6607    }
6608
6609    /// Combined set-match + EOF accounting + child append (ATN token-set
6610    /// variant).
6611    #[inline]
6612    pub fn match_token_set_into(
6613        &mut self,
6614        token_set: ParserIntervalSet<'_>,
6615        follow_state: usize,
6616        atn: &Atn,
6617        context: &mut ParserRuleContext,
6618        consumed_eof: &mut bool,
6619    ) -> Result<(), AntlrError> {
6620        let m = self.match_token_set_recovering(token_set, follow_state, atn)?;
6621        *consumed_eof |= m.consumed_eof();
6622        for child in m.into_child_iter() {
6623            self.add_parse_child(context, child);
6624        }
6625        Ok(())
6626    }
6627
6628    /// Combined set-match + EOF accounting + child append (inline intervals
6629    /// variant).
6630    #[inline]
6631    pub fn match_set_into(
6632        &mut self,
6633        intervals: &[(i32, i32)],
6634        follow_state: usize,
6635        atn: &Atn,
6636        context: &mut ParserRuleContext,
6637        consumed_eof: &mut bool,
6638    ) -> Result<(), AntlrError> {
6639        let m = self.match_set_recovering(intervals, follow_state, atn)?;
6640        *consumed_eof |= m.consumed_eof();
6641        for child in m.into_child_iter() {
6642            self.add_parse_child(context, child);
6643        }
6644        Ok(())
6645    }
6646
6647    /// Combined not-set-match + EOF accounting + child append (ATN token-set
6648    /// complement variant).
6649    #[allow(clippy::too_many_arguments)]
6650    #[inline]
6651    pub fn match_not_token_set_into(
6652        &mut self,
6653        token_set: ParserIntervalSet<'_>,
6654        min_vocabulary: i32,
6655        max_vocabulary: i32,
6656        follow_state: usize,
6657        atn: &Atn,
6658        context: &mut ParserRuleContext,
6659        consumed_eof: &mut bool,
6660    ) -> Result<(), AntlrError> {
6661        let m = self.match_not_token_set_recovering(
6662            token_set,
6663            min_vocabulary,
6664            max_vocabulary,
6665            follow_state,
6666            atn,
6667        )?;
6668        *consumed_eof |= m.consumed_eof();
6669        for child in m.into_child_iter() {
6670            self.add_parse_child(context, child);
6671        }
6672        Ok(())
6673    }
6674
6675    /// Combined not-set-match + EOF accounting + child append (inline intervals
6676    /// complement variant).
6677    #[allow(clippy::too_many_arguments)]
6678    #[inline]
6679    pub fn match_not_set_into(
6680        &mut self,
6681        intervals: &[(i32, i32)],
6682        min_vocabulary: i32,
6683        max_vocabulary: i32,
6684        follow_state: usize,
6685        atn: &Atn,
6686        context: &mut ParserRuleContext,
6687        consumed_eof: &mut bool,
6688    ) -> Result<(), AntlrError> {
6689        let m = self.match_not_set_recovering(
6690            intervals,
6691            min_vocabulary,
6692            max_vocabulary,
6693            follow_state,
6694            atn,
6695        )?;
6696        *consumed_eof |= m.consumed_eof();
6697        for child in m.into_child_iter() {
6698            self.add_parse_child(context, child);
6699        }
6700        Ok(())
6701    }
6702
6703    fn release_tree_scratch_if_idle(&mut self) {
6704        if self.rule_context_stack.is_empty() {
6705            self.tree.release_scratch();
6706        }
6707    }
6708
6709    /// Finishes a generated parser rule and returns its parse-tree node.
6710    pub fn finish_rule(&mut self, mut context: ParserRuleContext, consumed_eof: bool) -> ParseTree {
6711        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6712        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6713            self.set_context_stop(&mut context, token);
6714        }
6715        let node = self.rule_node(context);
6716        self.exit_rule();
6717        self.release_tree_scratch_if_idle();
6718        node
6719    }
6720
6721    /// Recovers a generated rule catch block after a committed mismatch.
6722    ///
6723    /// ANTLR's generated parsers catch recognition errors inside each rule,
6724    /// report the original error, then consume unexpected tokens until the
6725    /// caller's recovery set can resume. Tokens consumed during recovery become
6726    /// error nodes in the current rule context.
6727    pub fn recover_generated_rule(
6728        &mut self,
6729        context: &mut ParserRuleContext,
6730        atn: &Atn,
6731        error: AntlrError,
6732    ) {
6733        let diagnostic = self.generated_rule_error_diagnostic(error);
6734        self.push_generated_parser_diagnostic(diagnostic);
6735        self.generated_sync_expected = None;
6736        let error_index = self.input.index();
6737        let error_state = self.data.state();
6738        // Match ANTLR's lastErrorIndex/lastErrorStates failsafe: a recovery
6739        // token can also be in the caller's follow set, leaving the cursor
6740        // unchanged and allowing generated outer decisions to revisit the same
6741        // failed state forever.
6742        if self.generated_recovery_error_index == Some(error_index)
6743            && self.generated_recovery_error_states.contains(&error_state)
6744            && self.la(1) != TOKEN_EOF
6745            && let Some(token) = self.input.lt_id(1)
6746        {
6747            self.consume();
6748            let child = self.error_tree(token);
6749            self.add_parse_child(context, child);
6750        }
6751        let recovery_index = self.input.index();
6752        if self.generated_recovery_error_index != Some(recovery_index) {
6753            self.generated_recovery_error_index = Some(recovery_index);
6754            self.generated_recovery_error_states.clear();
6755        }
6756        self.generated_recovery_error_states.insert(error_state);
6757        let recovery_symbols = self.context_expected_symbols(atn);
6758        loop {
6759            let symbol = self.la(1);
6760            if symbol == TOKEN_EOF || recovery_symbols.contains(&symbol) {
6761                break;
6762            }
6763            let Some(token) = self.input.lt_id(1) else {
6764                break;
6765            };
6766            self.consume();
6767            let child = self.error_tree(token);
6768            self.add_parse_child(context, child);
6769        }
6770        self.record_syntax_errors(1);
6771    }
6772
6773    fn reset_generated_recovery_state(&mut self) {
6774        if self.generated_recovery_error_index.is_some() {
6775            self.generated_recovery_error_index = None;
6776            self.generated_recovery_error_states.clear();
6777        }
6778    }
6779
6780    fn push_generated_parser_diagnostic(&mut self, diagnostic: ParserDiagnostic) {
6781        if self
6782            .generated_parser_diagnostics
6783            .iter()
6784            .any(|existing| existing == &diagnostic)
6785        {
6786            return;
6787        }
6788        self.generated_parser_diagnostics.push(diagnostic);
6789    }
6790
6791    fn generated_rule_error_diagnostic(&self, error: AntlrError) -> ParserDiagnostic {
6792        match error {
6793            // The anchor recorded where the error was built wins over the
6794            // current lookahead: prediction restores the cursor, so lt(1)
6795            // here can point at the decision start rather than the error.
6796            AntlrError::ParserError {
6797                line,
6798                column,
6799                message,
6800                offending,
6801            } => ParserDiagnostic {
6802                line,
6803                column,
6804                message,
6805                offending,
6806            },
6807            AntlrError::MismatchedInput { expected, found } => diagnostic_for_token(
6808                self.input.lt(1),
6809                format!("mismatched input {found} expecting {expected}"),
6810            ),
6811            AntlrError::NoViableAlternative { input } => diagnostic_for_token(
6812                self.input.lt(1),
6813                format!("no viable alternative at input {input}"),
6814            ),
6815            AntlrError::LexerError {
6816                line,
6817                column,
6818                message,
6819            } => ParserDiagnostic {
6820                line,
6821                column,
6822                message,
6823                offending: None,
6824            },
6825            AntlrError::Unsupported(message) => diagnostic_for_token(self.input.lt(1), message),
6826        }
6827    }
6828
6829    /// Finishes a generated left-recursive parser rule and returns its parse-tree node.
6830    pub fn finish_recursion_rule(
6831        &mut self,
6832        mut context: ParserRuleContext,
6833        consumed_eof: bool,
6834    ) -> ParseTree {
6835        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
6836        if let Some(token) = stop_index.and_then(|index| self.token_id_at(index)) {
6837            self.set_context_stop(&mut context, token);
6838        }
6839        let node = self.rule_node(context);
6840        self.unroll_recursion_context();
6841        self.release_tree_scratch_if_idle();
6842        node
6843    }
6844
6845    /// Enters a generated left-recursive rule at `precedence`.
6846    pub fn enter_recursion_rule(
6847        &mut self,
6848        state: isize,
6849        rule_index: usize,
6850        precedence: i32,
6851    ) -> ParserRuleContext {
6852        self.precedence_stack.push(precedence);
6853        self.recursion_expansion_marks
6854            .push(self.recursion_expansions);
6855        self.enter_rule(state, rule_index)
6856    }
6857
6858    /// Replaces the current context while expanding a left-recursive rule.
6859    pub fn push_new_recursion_context(
6860        &mut self,
6861        state: isize,
6862        rule_index: usize,
6863    ) -> ParserRuleContext {
6864        self.set_state(state);
6865        // Counts toward the depth cap: upstream treats this as rule entry
6866        // (`Parser.pushNewRecursionContext` fires `triggerEnterRuleEvent`).
6867        self.recursion_expansions += 1;
6868        ParserRuleContext::new(rule_index, state)
6869    }
6870
6871    /// Wraps the previous left-recursive context before parsing the next
6872    /// recursive operator alternative.
6873    pub fn push_new_recursion_context_with_previous(
6874        &mut self,
6875        state: isize,
6876        rule_index: usize,
6877        current: &mut ParserRuleContext,
6878    ) {
6879        self.set_state(state);
6880        // Counts toward the depth cap: each operator iteration deepens the
6881        // parse tree one level without pushing a rule frame, and upstream
6882        // fires a rule-entry listener event for it. The parse-listener enter
6883        // event for this expansion fires from the generated loop's probe
6884        // just before this call, where a listener abort can propagate.
6885        self.recursion_expansions += 1;
6886        if let Some(stop) = self
6887            .rule_stop_token_index(self.input.index(), false)
6888            .and_then(|index| self.token_id_at(index))
6889        {
6890            self.set_context_stop(current, stop);
6891        }
6892        let invoking_state = current.invoking_state();
6893        let start = current.start_id();
6894        let mut replacement = ParserRuleContext::new(rule_index, invoking_state);
6895        if start.is_some() {
6896            replacement.set_start_from_context(current);
6897        }
6898        let previous = std::mem::replace(current, replacement);
6899        if self.build_parse_trees {
6900            let previous = self.rule_node(previous);
6901            self.tree.add_child(current, previous);
6902        }
6903    }
6904
6905    /// Leaves a generated left-recursive rule.
6906    pub fn unroll_recursion_context(&mut self) {
6907        if self.precedence_stack.len() > 1 {
6908            self.precedence_stack.pop();
6909        }
6910        // Parse-listener exits for expansions fire inside the generated
6911        // operator loop (top of each pass, upstream's `recRuleSetPrevCtx`),
6912        // and the dispatch wrapper's exit covers the final live context —
6913        // upstream's `unrollRecursionContexts` walks exactly one link, so no
6914        // batched exits happen here. Only the depth-cap accounting rewinds.
6915        if let Some(mark) = self.recursion_expansion_marks.pop() {
6916            self.recursion_expansions = mark;
6917        }
6918        self.exit_rule();
6919    }
6920
6921    /// Predicts a generated left-recursive loop from one-token lookahead.
6922    ///
6923    /// `Some(true)` enters the operator alternative, `Some(false)` exits, and
6924    /// `None` means caller overlap, a dangerous multi-token prefix, or an
6925    /// unresolved semantic predicate requires full `StarLoopEntry` adaptive
6926    /// prediction (which includes the exit alt and precedence filtering).
6927    ///
6928    /// Single-token operators and multi-token prefixes that do not shadow a
6929    /// lower-precedence single-token operator keep the one-token enter fast path.
6930    ///
6931    /// Multi-token prefixes that **do** shadow a lower-precedence single-token
6932    /// operator must not force enter; the adaptive decision may need to select
6933    /// the loop exit instead.
6934    pub fn left_recursive_loop_enter_prediction(
6935        &mut self,
6936        atn: &Atn,
6937        state_number: usize,
6938        precedence: i32,
6939    ) -> Option<bool> {
6940        let symbol = self.la(1);
6941        if symbol == TOKEN_EOF {
6942            return Some(false);
6943        }
6944        let operator_lookahead =
6945            Self::cached_left_recursive_operator_lookahead(atn, state_number, precedence);
6946        let can_single = operator_lookahead.single_token.contains(symbol);
6947        let can_multi = operator_lookahead.multi_token_prefix.contains(symbol);
6948        let can_predicate = operator_lookahead.predicate_dependent.contains(symbol);
6949        if !can_single && !can_multi && !can_predicate {
6950            return Some(false);
6951        }
6952        if can_predicate && !can_single {
6953            return None;
6954        }
6955        // Multi-token-only at this precedence, but the same symbol is a
6956        // single-token operator at precedence 0: defer so exit can win when the
6957        // multi-token sequence does not actually match (e.g. `>` vs `>>`).
6958        if !can_single && can_multi && precedence > 0 {
6959            let baseline = Self::cached_left_recursive_operator_lookahead(atn, state_number, 0);
6960            if baseline.single_token.contains(symbol) {
6961                return None;
6962            }
6963        }
6964        let atn_key = SharedAtnCacheKey::for_atn(atn);
6965        let cached_overlap = self
6966            .left_recursive_caller_overlap_cache
6967            .iter()
6968            .flatten()
6969            .find(|entry| {
6970                entry.atn_key == atn_key
6971                    && entry.state_number == state_number
6972                    && entry.symbol == symbol
6973                    && entry.context_version == self.rule_context_version
6974            })
6975            .map(|entry| entry.overlaps);
6976        let caller_overlaps = cached_overlap.unwrap_or_else(|| {
6977            let overlaps = caller_context_can_match_symbol_before_state(
6978                atn,
6979                self.prediction_context_return_states(atn),
6980                state_number,
6981                symbol,
6982            );
6983            if let Some(slot) = self
6984                .left_recursive_caller_overlap_cache
6985                .iter_mut()
6986                .find(|slot| slot.is_none())
6987            {
6988                *slot = Some(LeftRecursiveCallerOverlap {
6989                    atn_key,
6990                    state_number,
6991                    symbol,
6992                    context_version: self.rule_context_version,
6993                    overlaps,
6994                });
6995            }
6996            overlaps
6997        });
6998        if caller_overlaps {
6999            return None;
7000        }
7001        Some(true)
7002    }
7003
7004    fn cached_left_recursive_operator_lookahead(
7005        atn: &Atn,
7006        state_number: usize,
7007        precedence: i32,
7008    ) -> Rc<LeftRecursiveOperatorLookahead> {
7009        with_shared_atn_caches(atn, |cache| {
7010            let key = (state_number, precedence);
7011            if let Some(cached) = cache.left_recursive_operator_lookahead.get(&key) {
7012                return Rc::clone(cached);
7013            }
7014            let lookahead = Rc::new(left_recursive_operator_lookahead(
7015                atn,
7016                state_number,
7017                precedence,
7018            ));
7019            cache
7020                .left_recursive_operator_lookahead
7021                .insert(key, Rc::clone(&lookahead));
7022            lookahead
7023        })
7024    }
7025
7026    /// Checks whether a generated left-recursive loop can unambiguously enter
7027    /// its operator alternative from one-token lookahead.
7028    pub fn left_recursive_loop_enter_matches(
7029        &mut self,
7030        atn: &Atn,
7031        state_number: usize,
7032        precedence: i32,
7033    ) -> bool {
7034        self.left_recursive_loop_enter_prediction(atn, state_number, precedence) == Some(true)
7035    }
7036
7037    /// Implements generated `precpred(_ctx, k)` checks.
7038    pub fn precpred(&self, precedence: i32) -> bool {
7039        precedence >= self.precedence_stack.last().copied().unwrap_or_default()
7040    }
7041
7042    /// Evaluates a generated parser semantic predicate at the current input
7043    /// position.
7044    pub fn parser_semantic_predicate_matches(
7045        &mut self,
7046        predicates: &[(usize, usize, ParserPredicate)],
7047        rule_index: usize,
7048        pred_index: usize,
7049    ) -> bool {
7050        self.parser_semantic_predicate_matches_inner(predicates, rule_index, pred_index, None)
7051    }
7052
7053    /// Evaluates a generated parser semantic predicate with the current integer
7054    /// rule argument exposed as `$_p`/`$i` metadata where applicable.
7055    pub fn parser_semantic_predicate_matches_with_local(
7056        &mut self,
7057        predicates: &[(usize, usize, ParserPredicate)],
7058        rule_index: usize,
7059        pred_index: usize,
7060        local_int_arg: i32,
7061    ) -> bool {
7062        self.parser_semantic_predicate_matches_inner(
7063            predicates,
7064            rule_index,
7065            pred_index,
7066            Some((rule_index, i64::from(local_int_arg))),
7067        )
7068    }
7069
7070    fn parser_semantic_predicate_matches_inner(
7071        &mut self,
7072        predicates: &[(usize, usize, ParserPredicate)],
7073        rule_index: usize,
7074        pred_index: usize,
7075        local_int_arg: Option<(usize, i64)>,
7076    ) -> bool {
7077        let index = self.input.index();
7078        let member_values = self.int_members.clone();
7079        self.parser_predicate_matches(PredicateEval {
7080            index,
7081            rule_index,
7082            pred_index,
7083            predicates,
7084            semantics: None,
7085            context: None,
7086            local_int_arg,
7087            member_values: &member_values,
7088        })
7089    }
7090
7091    /// Evaluates a generated parser semantic predicate with access to the
7092    /// current generated rule context.
7093    pub fn parser_semantic_predicate_matches_with_context_and_local(
7094        &mut self,
7095        predicates: &[(usize, usize, ParserPredicate)],
7096        rule_index: usize,
7097        pred_index: usize,
7098        context: &ParserRuleContext,
7099        local_int_arg: i32,
7100    ) -> bool {
7101        let index = self.input.index();
7102        let member_values = self.int_members.clone();
7103        self.parser_predicate_matches(PredicateEval {
7104            index,
7105            rule_index,
7106            pred_index,
7107            predicates,
7108            semantics: None,
7109            context: Some(context),
7110            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
7111            member_values: &member_values,
7112        })
7113    }
7114
7115    /// Evaluates a generated `SemIR` parser predicate with access to the current
7116    /// generated rule context.
7117    pub fn parser_semantic_ir_predicate_matches_with_context_and_local(
7118        &mut self,
7119        semantics: &ParserSemantics,
7120        rule_index: usize,
7121        pred_index: usize,
7122        context: &ParserRuleContext,
7123        local_int_arg: i32,
7124    ) -> bool {
7125        let index = self.input.index();
7126        let member_values = self.int_members.clone();
7127        self.parser_predicate_matches(PredicateEval {
7128            index,
7129            rule_index,
7130            pred_index,
7131            predicates: &[],
7132            semantics: Some(semantics),
7133            context: Some(context),
7134            local_int_arg: Some((rule_index, i64::from(local_int_arg))),
7135            member_values: &member_values,
7136        })
7137    }
7138
7139    /// Returns a generated fail-option message for a parser semantic
7140    /// predicate coordinate.
7141    pub fn parser_semantic_predicate_failure_message(
7142        &self,
7143        rule_index: usize,
7144        pred_index: usize,
7145        predicates: &[(usize, usize, ParserPredicate)],
7146    ) -> Option<&'static str> {
7147        self.parser_predicate_failure_message(rule_index, pred_index, predicates)
7148    }
7149
7150    /// Matches any non-EOF token.
7151    pub fn match_wildcard(&mut self) -> Result<ParseTree, AntlrError> {
7152        let current = self.input.lt_id(1).ok_or_else(|| AntlrError::ParserError {
7153            line: 0,
7154            column: 0,
7155            message: "missing current token".to_owned(),
7156            offending: None,
7157        })?;
7158        if self.token_type_for_id(current) == TOKEN_EOF {
7159            return Err(AntlrError::MismatchedInput {
7160                expected: "wildcard".to_owned(),
7161                found: self.vocabulary().display_name(TOKEN_EOF),
7162            });
7163        }
7164        self.reset_generated_recovery_state();
7165        self.consume();
7166        Ok(self.terminal_tree(current))
7167    }
7168
7169    /// Generated parser synchronization hook. The current interpreter owns
7170    /// recovery; direct generated methods can call this as a no-op until the
7171    /// generated recovery strategy is expanded.
7172    #[allow(clippy::unnecessary_wraps)]
7173    pub fn sync(&mut self, state: isize) -> Result<(), AntlrError> {
7174        self.set_state(state);
7175        Ok(())
7176    }
7177
7178    /// Synchronizes a generated parser decision against the ATN lookahead set.
7179    ///
7180    /// ANTLR generated parsers call the error strategy before optional and loop
7181    /// decisions. When the current token cannot start any alternative, follow a
7182    /// nullable exit, or be deleted before a later synchronization token, the
7183    /// generated Rust method reports that decision-level mismatch instead of
7184    /// descending into a child rule that cannot start at the current token.
7185    pub fn sync_decision(
7186        &mut self,
7187        atn: &Atn,
7188        state_number: usize,
7189        _current_context_empty: bool,
7190        loop_back: bool,
7191    ) -> Result<Vec<ParseTree>, AntlrError> {
7192        self.set_state(isize::try_from(state_number).unwrap_or(isize::MAX));
7193        self.generated_sync_expected = None;
7194        let Some(state) = atn.state(state_number) else {
7195            return Ok(Vec::new());
7196        };
7197        let Some(rule_index) = state.rule_index() else {
7198            return Ok(Vec::new());
7199        };
7200        let Some(rule_stop) = atn.rule_to_stop_state().get(rule_index) else {
7201            return Ok(Vec::new());
7202        };
7203        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7204        let symbol = self.la(1);
7205        let mut has_expected_symbols = false;
7206        let mut nullable = false;
7207        // Whether EOF is an EXPLICIT expected token of this decision (a real `EOF`
7208        // reference in the grammar, e.g. `A* EOF`), as opposed to merely the
7209        // implicit rule-follow that a nullable exit inherits (e.g. a start rule's
7210        // end). Only an explicit EOF makes a token-before-EOF genuinely extraneous
7211        // and worth deleting; an implicit-follow EOF means the loop should simply
7212        // exit and leave the token for the (absent) caller — matching ANTLR, which
7213        // exits the loop via prediction rather than consuming up to a synthetic EOF.
7214        let mut explicit_eof_expected = false;
7215        for transition in &entry.transitions {
7216            if transition.symbols.contains(symbol) {
7217                return Ok(Vec::new());
7218            }
7219            has_expected_symbols |= !transition.symbols.is_empty();
7220            nullable |= transition.nullable;
7221            explicit_eof_expected |= transition.symbols.contains(TOKEN_EOF);
7222        }
7223        // Java's DefaultErrorStrategy.sync returns as soon as nextTokens
7224        // contains EPSILON. It remembers the decision/context expected set for
7225        // a later mismatch, but must not attempt single-token deletion or
7226        // loop-back recovery first: a nullable decision leaves the current
7227        // token to its caller even when that token is not in the context-free
7228        // FOLLOW set.
7229        if nullable {
7230            // Valid exits only need a membership probe. Materialize the full
7231            // expected set below solely when a later caller mismatch may need
7232            // the combined decision/context diagnostic.
7233            if self.context_expected_contains(atn, symbol) {
7234                return Ok(Vec::new());
7235            }
7236            let mut expected = self.context_expected_token_set(atn);
7237            for transition in &entry.transitions {
7238                expected.extend_from(&transition.symbols);
7239            }
7240            self.generated_sync_expected = Some(expected);
7241            return Ok(Vec::new());
7242        }
7243        if !has_expected_symbols {
7244            return Ok(Vec::new());
7245        }
7246        let mut expected = TokenBitSet::default();
7247        for transition in &entry.transitions {
7248            expected.extend_from(&transition.symbols);
7249        }
7250        // ANTLR's `DefaultErrorStrategy.sync` recovers differently by decision kind:
7251        // a loop-BACK sync (STAR_LOOP_BACK / PLUS_LOOP_BACK — reached only after at
7252        // least one iteration) does `consumeUntil` the follow set — multi-token
7253        // deletion, one error per skipped token across iterations; a loop ENTRY
7254        // (STAR_LOOP_ENTRY) and a plain optional/block entry (BLOCK_START /
7255        // *-block / +-block starts) do `singleTokenDeletion` — delete the one
7256        // unexpected token only when LA(2) is expected, otherwise report a mismatch
7257        // and leave recovery to the rule.
7258        //
7259        // The generated loop always presents the loop-ENTRY state to this method on
7260        // every pass, so `state.kind()` cannot distinguish entry from back; the caller
7261        // passes `loop_back` (false on a `*` loop's first sync / on a block, true once
7262        // an iteration has been taken, and true on a `+` loop's first sync since its
7263        // mandatory first element is iteration 1). Treating a loop entry as a
7264        // loop-back would over-consume (e.g. `s: A* EOF;` on `c c` would delete both
7265        // `c`s, which ANTLR rejects with `mismatched input`).
7266        let loop_sync = loop_back;
7267        if symbol != TOKEN_EOF {
7268            let mut cursor = self.input.index();
7269            let mut skipped = Vec::new();
7270            loop {
7271                let current = self.token_type_at(cursor);
7272                if current == TOKEN_EOF {
7273                    break;
7274                }
7275                skipped.push(cursor);
7276                let next = self.consume_index(cursor, current);
7277                if next == cursor {
7278                    break;
7279                }
7280                let next_symbol = self.token_type_at(next);
7281                // Stop (and delete the skipped tokens as error nodes) when the next
7282                // token is a real expected continuation. EOF counts only when it is
7283                // an EXPLICIT grammar token (`A* EOF`): then the deleted tokens are
7284                // genuinely extraneous and the generated EOF match consumes the real
7285                // EOF afterwards. An implicit-follow EOF (a nullable exit's inherited
7286                // rule-follow) does NOT count — the loop must exit and leave the
7287                // token, as ANTLR does, instead of deleting up to a synthetic EOF.
7288                let next_is_expected_stop = if next_symbol == TOKEN_EOF {
7289                    explicit_eof_expected
7290                } else {
7291                    expected.contains(next_symbol)
7292                };
7293                if next_is_expected_stop {
7294                    let current_token = self.input.lt(1);
7295                    let expected_symbols = expected.to_btree_set();
7296                    let message = format!(
7297                        "extraneous input {} expecting {}",
7298                        current_token
7299                            .as_ref()
7300                            .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7301                        self.expected_symbols_display(&expected_symbols)
7302                    );
7303                    self.push_generated_parser_diagnostic(diagnostic_for_token(
7304                        current_token,
7305                        message,
7306                    ));
7307                    self.record_syntax_errors(1);
7308                    let mut children = Vec::with_capacity(skipped.len());
7309                    for index in skipped {
7310                        if let Some(token) = self.token_id_at(index) {
7311                            self.consume();
7312                            children.push(self.error_tree(token));
7313                        }
7314                    }
7315                    if !loop_sync {
7316                        self.reset_generated_recovery_state();
7317                    }
7318                    return Ok(children);
7319                }
7320                // A non-loop block entry deletes at most one token (single-token
7321                // deletion): if LA(2) is not expected, stop scanning so the mismatch
7322                // is reported at the first token instead of skipping ahead.
7323                if !loop_sync {
7324                    break;
7325                }
7326                cursor = next;
7327            }
7328        }
7329        let current = self.input.lt(1);
7330        let expected_symbols = expected.to_btree_set();
7331        Err(AntlrError::ParserError {
7332            line: current.as_ref().map(Token::line).unwrap_or_default(),
7333            column: current.as_ref().map(Token::column).unwrap_or_default(),
7334            message: format!(
7335                "mismatched input {} expecting {}",
7336                current
7337                    .as_ref()
7338                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
7339                self.expected_symbols_display(&expected_symbols)
7340            ),
7341            offending: current.as_ref().map(Token::token_id),
7342        })
7343    }
7344
7345    /// Returns a generated-parser prediction when one token of lookahead
7346    /// uniquely selects an alternative for `state_number`.
7347    ///
7348    /// This mirrors the interpreter's LL(1) commit point and lets generated
7349    /// recursive-descent methods avoid invoking the adaptive simulator for
7350    /// simple optional/block/loop decisions.
7351    pub fn ll1_decision_prediction(
7352        &mut self,
7353        atn: &Atn,
7354        state_number: usize,
7355    ) -> Option<ParserAtnPrediction> {
7356        let state = atn.state(state_number)?;
7357        if state.precedence_rule_decision() {
7358            return None;
7359        }
7360        let rule_stop = state
7361            .rule_index()
7362            .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))?;
7363        let symbol = self.la(1);
7364        let entry = self.cached_decision_lookahead(atn, state, rule_stop);
7365        ll1_greedy_alt(&entry, symbol, state.non_greedy()).map(|alt| ParserAtnPrediction {
7366            alt: alt + 1,
7367            requires_full_context: false,
7368            has_semantic_context: false,
7369            diagnostic: None,
7370        })
7371    }
7372
7373    fn context_expected_symbols(&mut self, atn: &Atn) -> BTreeSet<i32> {
7374        let mut expected = BTreeSet::new();
7375        for index in (1..self.rule_context_stack.len()).rev() {
7376            let invoking_state = self.rule_context_stack[index].invoking_state;
7377            let Ok(state_number) = usize::try_from(invoking_state) else {
7378                continue;
7379            };
7380            let Some(Transition::Rule { follow_state, .. }) = atn
7381                .state(state_number)
7382                .and_then(|state| state.transitions().first())
7383                .map(ParserTransition::data)
7384            else {
7385                continue;
7386            };
7387            let return_state = follow_state;
7388            expected.extend(self.cached_state_expected_symbols(atn, return_state).iter());
7389            if !self.cached_state_can_reach_rule_stop(atn, return_state) {
7390                return expected;
7391            }
7392        }
7393        expected.insert(TOKEN_EOF);
7394        expected
7395    }
7396
7397    fn context_expected_token_set(&mut self, atn: &Atn) -> TokenBitSet {
7398        let mut expected = TokenBitSet::default();
7399        for index in (1..self.rule_context_stack.len()).rev() {
7400            let invoking_state = self.rule_context_stack[index].invoking_state;
7401            let Ok(state_number) = usize::try_from(invoking_state) else {
7402                continue;
7403            };
7404            let Some(Transition::Rule { follow_state, .. }) = atn
7405                .state(state_number)
7406                .and_then(|state| state.transitions().first())
7407                .map(ParserTransition::data)
7408            else {
7409                continue;
7410            };
7411            expected.extend_from(&self.cached_state_expected_token_set(atn, follow_state));
7412            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7413                return expected;
7414            }
7415        }
7416        expected.insert(TOKEN_EOF);
7417        expected
7418    }
7419
7420    /// Reports whether `symbol` is in `context_expected_token_set(atn)`
7421    /// without materializing the union.
7422    ///
7423    /// The walk follows the same rule-stack return chain as adaptive
7424    /// prediction. Valid nullable exits normally match the innermost frame,
7425    /// keeping their synchronization path to one cached membership probe.
7426    fn context_expected_contains(&mut self, atn: &Atn, symbol: i32) -> bool {
7427        for index in (1..self.rule_context_stack.len()).rev() {
7428            let invoking_state = self.rule_context_stack[index].invoking_state;
7429            let Ok(state_number) = usize::try_from(invoking_state) else {
7430                continue;
7431            };
7432            let Some(Transition::Rule { follow_state, .. }) = atn
7433                .state(state_number)
7434                .and_then(|state| state.transitions().first())
7435                .map(ParserTransition::data)
7436            else {
7437                continue;
7438            };
7439            if self
7440                .cached_state_expected_token_set(atn, follow_state)
7441                .contains(symbol)
7442            {
7443                return true;
7444            }
7445            if !self.cached_state_can_reach_rule_stop(atn, follow_state) {
7446                return false;
7447            }
7448        }
7449        symbol == TOKEN_EOF
7450    }
7451
7452    /// Builds a generated no-viable-alternative parser error.
7453    pub fn no_viable_alternative_error(&self, start_index: usize) -> AntlrError {
7454        let error_index = self.input.index();
7455        self.no_viable_alternative_error_at(start_index, error_index)
7456    }
7457
7458    /// Builds a generated no-viable-alternative parser error at the simulator's
7459    /// failing lookahead index. `adaptive_predict` restores the input cursor
7460    /// before returning, so generated parsers have to pass the recorded index
7461    /// explicitly to preserve ANTLR's LL(k) diagnostic span.
7462    pub fn no_viable_alternative_error_at(
7463        &self,
7464        start_index: usize,
7465        error_index: usize,
7466    ) -> AntlrError {
7467        let diagnostic = self.no_viable_alternative(start_index, error_index);
7468        AntlrError::ParserError {
7469            line: diagnostic.line,
7470            column: diagnostic.column,
7471            message: diagnostic.message,
7472            offending: diagnostic.offending,
7473        }
7474    }
7475
7476    /// Builds a generated failed-predicate parser error.
7477    pub fn failed_predicate_error(&self, message: impl Into<String>) -> AntlrError {
7478        let current = self.input.lt(1);
7479        AntlrError::ParserError {
7480            line: current.as_ref().map(Token::line).unwrap_or_default(),
7481            column: current.as_ref().map(Token::column).unwrap_or_default(),
7482            message: format!("rule failed predicate: {}", message.into()),
7483            offending: current.as_ref().map(Token::token_id),
7484        }
7485    }
7486
7487    /// Builds a generated parser error for a semantic predicate with ANTLR's
7488    /// `<fail='...'>` option.
7489    pub fn failed_predicate_option_error(
7490        &self,
7491        rule_index: usize,
7492        message: impl Into<String>,
7493    ) -> AntlrError {
7494        let current = self.input.lt(1);
7495        let rule_name = self
7496            .rule_names()
7497            .get(rule_index)
7498            .map_or_else(|| rule_index.to_string(), Clone::clone);
7499        AntlrError::ParserError {
7500            line: current.as_ref().map(Token::line).unwrap_or_default(),
7501            column: current.as_ref().map(Token::column).unwrap_or_default(),
7502            message: format!("rule {rule_name} {}", message.into()),
7503            offending: current.as_ref().map(Token::token_id),
7504        }
7505    }
7506
7507    /// Builds a generated parser-action event at the current input position.
7508    pub fn parser_action_at_current(
7509        &mut self,
7510        source_state: usize,
7511        rule_index: usize,
7512        start_index: usize,
7513        consumed_eof: bool,
7514    ) -> ParserAction {
7515        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7516        ParserAction::new(source_state, rule_index, start_index, stop_index)
7517    }
7518
7519    /// Builds an indexed generated parser-action event at the current input position.
7520    pub fn parser_action_at_current_indexed(
7521        &mut self,
7522        source_state: usize,
7523        rule_index: usize,
7524        action_index: usize,
7525        start_index: usize,
7526        consumed_eof: bool,
7527    ) -> ParserAction {
7528        let stop_index = self.rule_stop_token_index(self.input.index(), consumed_eof);
7529        ParserAction::new_indexed(
7530            source_state,
7531            rule_index,
7532            action_index,
7533            start_index,
7534            stop_index,
7535        )
7536    }
7537
7538    /// Offers a committed parser action event to the user semantic hook.
7539    ///
7540    /// Generated parsers call this for action source states that were present
7541    /// in the ATN but not translated into a built-in Rust action template.
7542    pub fn parser_action_hook(&mut self, action: ParserAction, tree: ParseTree) -> bool {
7543        self.parser_action_hook_inner(action, None, Some(tree), None, true)
7544    }
7545
7546    /// Offers an action to semantic hooks at its committed grammar position.
7547    ///
7548    /// The current rule context contains children completed before the action;
7549    /// the full rule tree is not available until the rule returns.
7550    pub fn parser_action_hook_with_context(
7551        &mut self,
7552        action: ParserAction,
7553        context: &ParserRuleContext,
7554    ) -> bool {
7555        self.parser_action_hook_inner(action, Some(context), None, None, true)
7556    }
7557
7558    /// Offers an action with the current generated rule's integer argument.
7559    ///
7560    /// Generated parameterized rules use the same integer carrier as generated
7561    /// predicate evaluation. The context exposes it through
7562    /// [`ParserSemCtx::local_int_arg`].
7563    pub fn parser_action_hook_with_context_and_local(
7564        &mut self,
7565        action: ParserAction,
7566        context: &ParserRuleContext,
7567        local_int_arg: i32,
7568    ) -> bool {
7569        self.parser_action_hook_inner(
7570            action,
7571            Some(context),
7572            None,
7573            Some((action.rule_index(), i64::from(local_int_arg))),
7574            true,
7575        )
7576    }
7577
7578    /// Offers a rule-init action at rule entry while preserving legacy replay.
7579    ///
7580    /// A declined init is returned to the generated caller, so it is not an
7581    /// unhandled action yet and must not trip the fail-loud policy here.
7582    fn parser_rule_init_hook_with_context(
7583        &mut self,
7584        action: ParserAction,
7585        context: &ParserRuleContext,
7586        local_int_arg: Option<(usize, i64)>,
7587    ) -> bool {
7588        debug_assert!(action.is_rule_init());
7589        self.parser_action_hook_inner(action, Some(context), None, local_int_arg, false)
7590    }
7591
7592    fn parser_action_hook_inner(
7593        &mut self,
7594        action: ParserAction,
7595        context: Option<&ParserRuleContext>,
7596        tree: Option<ParseTree>,
7597        local_int_arg: Option<(usize, i64)>,
7598        record_unhandled: bool,
7599    ) -> bool {
7600        let rule_index = action.rule_index();
7601        let rule_name = self.rule_names().get(rule_index).cloned();
7602        let input = &mut self.input;
7603        let semantic_hooks = &mut self.semantic_hooks;
7604        let member_values = &self.int_members;
7605        let mut ctx = ParserSemCtx {
7606            input,
7607            tree_storage: &self.tree,
7608            rule_index,
7609            coordinate_index: action.action_index().unwrap_or(usize::MAX),
7610            rule_name,
7611            context,
7612            tree,
7613            local_int_arg,
7614            member_values,
7615            action: Some(action),
7616        };
7617        let handled = semantic_hooks.action(&mut ctx, action);
7618        // This action reached the hook because it had no translated arm. If no
7619        // hook handled it either (`SemanticHooks::action` returns `false`), the
7620        // committed action is silently dropped — record it so the parse entry
7621        // can fail loud under the fail-loud boundary, mirroring unknown
7622        // predicates. `assume-*` policies opt out of the fail-loud recording.
7623        if record_unhandled
7624            && !handled
7625            && matches!(self.unknown_predicate_policy, UnknownSemanticPolicy::Error)
7626        {
7627            let coordinate = (rule_index, action.source_state());
7628            if !self.unhandled_action_hits.contains(&coordinate) {
7629                self.unhandled_action_hits.push(coordinate);
7630            }
7631        }
7632        handled
7633    }
7634
7635    /// Attempts to execute a whole generated rule by committing simulator
7636    /// decisions directly. Unsupported constructs or decisions that need
7637    /// full-context / predicate evaluation restore the input cursor and fall
7638    /// back to [`Self::parse_atn_rule`].
7639    pub fn parse_atn_rule_adaptive_or_fallback<'atn>(
7640        &mut self,
7641        atn: &'atn Atn,
7642        simulator: &mut ParserAtnSimulator<'atn>,
7643        rule_index: usize,
7644    ) -> Result<ParseTree, AntlrError> {
7645        let start_index = self.current_visible_index();
7646        self.clear_prediction_diagnostics();
7647        self.reset_per_parse_caches();
7648        self.reset_recognition_arena();
7649        let tree_checkpoint = self.tree.checkpoint();
7650        let mut decision_by_state = vec![None; atn.states().len()];
7651        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
7652            if let Some(slot) = decision_by_state.get_mut(state_number) {
7653                *slot = Some(decision);
7654            }
7655        }
7656
7657        let result = DirectAdaptiveParser {
7658            parser: self,
7659            atn,
7660            simulator,
7661            decision_by_state,
7662            steps: 0,
7663        }
7664        .parse_rule(rule_index, -1, 0);
7665
7666        match result {
7667            Ok(tree) => {
7668                self.report_token_source_errors();
7669                self.release_tree_scratch_if_idle();
7670                Ok(tree)
7671            }
7672            Err(DirectAdaptiveParseControl::Fallback(reason)) => {
7673                let _ = reason;
7674                self.tree.rollback(tree_checkpoint);
7675                self.input.seek(start_index);
7676                self.parse_atn_rule(atn, rule_index)
7677            }
7678        }
7679    }
7680
7681    /// Parses a generated rule by interpreting the parser ATN from the rule's
7682    /// start state to its stop state.
7683    ///
7684    /// The recognizer backtracks across alternatives and loop exits using token
7685    /// stream indices instead of committing to input consumption immediately.
7686    /// Once a viable ATN path is found, the parser commits the accepted token
7687    /// interval and returns a rule node whose children mirror every grammar
7688    /// rule invocation reached on that path, matching ANTLR's parse-tree
7689    /// shape.
7690    pub fn parse_atn_rule(
7691        &mut self,
7692        atn: &Atn,
7693        rule_index: usize,
7694    ) -> Result<ParseTree, AntlrError> {
7695        self.parse_atn_rule_with_precedence(atn, rule_index, 0)
7696    }
7697
7698    /// Parses a generated rule by interpreting the parser ATN with an initial
7699    /// left-recursive precedence threshold.
7700    pub fn parse_atn_rule_with_precedence(
7701        &mut self,
7702        atn: &Atn,
7703        rule_index: usize,
7704        precedence: i32,
7705    ) -> Result<ParseTree, AntlrError> {
7706        self.parse_atn_rule_with_precedence_inner(
7707            atn,
7708            rule_index,
7709            precedence,
7710            None,
7711            AltNumberTracking::default(),
7712        )
7713    }
7714
7715    fn parse_atn_rule_with_precedence_inner(
7716        &mut self,
7717        atn: &Atn,
7718        rule_index: usize,
7719        precedence: i32,
7720        predicate_context: Option<FastPredicateContext<'_>>,
7721        alt_tracking: AltNumberTracking,
7722    ) -> Result<ParseTree, AntlrError> {
7723        let report_unrecovered_error = self.is_top_level_entry();
7724        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
7725            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
7726        })?;
7727        let stop_state = atn
7728            .rule_to_stop_state()
7729            .get(rule_index)
7730            .filter(|state| *state != usize::MAX)
7731            .ok_or_else(|| {
7732                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
7733            })?;
7734
7735        let start_index = self.current_visible_index();
7736        self.clear_prediction_diagnostics();
7737        self.reset_per_parse_caches();
7738        self.reset_recognition_arena();
7739        let caller_follow_state = self.pending_invoking_follow_state(atn);
7740        self.fast_recovery_enabled = false;
7741        self.fast_token_nodes_enabled = false;
7742        self.fast_track_alt_numbers = alt_tracking.any();
7743        let top_request = FastRecognizeTopRequest {
7744            start_state,
7745            stop_state,
7746            start_index,
7747            precedence,
7748            caller_follow_state,
7749        };
7750        let first_pass = self.fast_recognize_top(atn, top_request, predicate_context);
7751        self.fast_token_nodes_enabled = self.build_parse_trees;
7752        let needs_tree_retry = matches!(
7753            &first_pass,
7754            Ok((outcome, _, _))
7755                if self.build_parse_trees
7756                    && self
7757                        .recognition_arena
7758                        .sequence_has_left_recursive_boundary(outcome.nodes)
7759        );
7760        let needs_retry = match &first_pass {
7761            // The FIRST-set prefilter trims speculative rule calls that can't
7762            // match the current lookahead — useful for perf on grammars with
7763            // many epsilon-reachable rules, but the trim also bypasses
7764            // single-token insertion / deletion recovery that ANTLR's
7765            // reference parser runs at the child rule's first consuming
7766            // transition. Retry without the prefilter whenever the first pass
7767            // either produced no outcome at all or produced a recovered
7768            // outcome (diagnostics non-empty), since the second pass might
7769            // surface a child-level recovery with cleaner diagnostics or
7770            // closer parity to ANTLR's tree shape. Left-recursive tree
7771            // boundaries also need the token-node pass; otherwise the fold has
7772            // no concrete left operand to wrap into ANTLR's recursive context.
7773            Err(_) => true,
7774            Ok((outcome, _, _)) => !outcome.diagnostics.is_empty() || needs_tree_retry,
7775        };
7776        let (outcome, _expected, alt_number) = if needs_retry {
7777            self.fast_first_set_prefilter = false;
7778            self.fast_recovery_enabled = false;
7779            let clean_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7780            let clean_selected = if needs_tree_retry {
7781                match clean_retry {
7782                    ok @ Ok(_) => ok,
7783                    Err(_) => first_pass,
7784                }
7785            } else {
7786                select_better_top_outcome(first_pass, clean_retry, &self.recognition_arena)
7787            };
7788            let selected = if clean_selected.is_err()
7789                || matches!(&clean_selected, Ok((outcome, _, _)) if !outcome.diagnostics.is_empty())
7790            {
7791                self.fast_recovery_enabled = true;
7792                let recovery_retry = self.fast_recognize_top(atn, top_request, predicate_context);
7793                select_better_top_outcome(clean_selected, recovery_retry, &self.recognition_arena)
7794            } else {
7795                clean_selected
7796            };
7797            self.fast_first_set_prefilter = true;
7798            self.fast_recovery_enabled = true;
7799            selected.map_err(|expected| {
7800                if predicate_context.is_some()
7801                    && let Some(error) = self.unknown_semantic_error()
7802                {
7803                    self.report_token_source_errors();
7804                    return error;
7805                }
7806                let error = self.recognition_error(rule_index, start_index, &expected);
7807                self.record_syntax_errors(1);
7808                self.report_token_source_errors();
7809                if report_unrecovered_error {
7810                    self.report_unrecovered_parser_error(&error);
7811                }
7812                error
7813            })?
7814        } else {
7815            first_pass.expect("first_pass is Ok in the no-retry branch")
7816        };
7817        if predicate_context.is_some()
7818            && let Some(error) = self.unknown_semantic_error()
7819        {
7820            self.report_token_source_errors();
7821            return Err(error);
7822        }
7823        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
7824        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
7825        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
7826        self.report_token_source_errors();
7827        let mut context = ParserRuleContext::with_child_capacity(
7828            rule_index,
7829            self.state(),
7830            if self.build_parse_trees {
7831                self.recognition_arena.sequence_len(outcome.nodes)
7832            } else {
7833                0
7834            },
7835        );
7836        if alt_tracking.public {
7837            context.set_alt_number(alt_number.max(1));
7838        }
7839        if alt_tracking.context {
7840            context.set_context_alt_number(alt_number);
7841        }
7842        if let Some(token) = self.token_id_at(start_index) {
7843            self.set_context_start(&mut context, token);
7844        }
7845        let stop_index = self.rule_stop_token_index(outcome.index, outcome.consumed_eof);
7846        if let Some(token) = stop_index.and_then(|token_index| self.token_id_at(token_index)) {
7847            self.set_context_stop(&mut context, token);
7848        }
7849        let live_root = if self.build_parse_trees {
7850            self.recognition_arena
7851                .fold_left_recursive_boundaries(outcome.nodes)
7852        } else {
7853            outcome.nodes
7854        };
7855        if self.build_parse_trees {
7856            if self
7857                .recognition_arena
7858                .sequence_has_explicit_token(live_root)
7859            {
7860                let mut cursor = live_root;
7861                while let Some(link) = self.recognition_arena.link(cursor) {
7862                    let child = self.arena_recognized_node_tree(
7863                        link.head,
7864                        alt_tracking.public,
7865                        alt_tracking.context,
7866                    )?;
7867                    self.tree.add_child(&mut context, child);
7868                    cursor = link.tail;
7869                }
7870            } else {
7871                self.add_arena_implicit_token_children(
7872                    &mut context,
7873                    start_index,
7874                    stop_index,
7875                    live_root,
7876                    alt_tracking,
7877                )?;
7878            }
7879        }
7880        self.finish_recognition_arena(live_root, outcome.diagnostics);
7881        self.input.seek(outcome.index);
7882
7883        let tree = self.rule_node(context);
7884        self.release_tree_scratch_if_idle();
7885        Ok(tree)
7886    }
7887
7888    fn pending_invoking_follow_state(&self, atn: &Atn) -> Option<usize> {
7889        let invoking_state = self.pending_invoking_states.last().copied()?;
7890        let state_number = usize::try_from(invoking_state).ok()?;
7891        match atn.state(state_number)?.transitions().first()?.data() {
7892            Transition::Rule { follow_state, .. } => Some(follow_state),
7893            _ => None,
7894        }
7895    }
7896
7897    #[cfg(test)]
7898    fn caller_follow_token_info(&mut self, index: usize) -> (i32, bool, bool) {
7899        caller_follow_token_info_for_stream(&mut self.input, index)
7900    }
7901
7902    /// Runs the fast recognizer once from the rule's start state and returns
7903    /// the best outcome or the per-attempt expected-token accumulator. The
7904    /// caller flips `fast_first_set_prefilter` between calls when a retry is
7905    /// needed, so the FIRST-set cache is left intact across both passes.
7906    fn fast_recognize_top(
7907        &mut self,
7908        atn: &Atn,
7909        request: FastRecognizeTopRequest,
7910        predicate_context: Option<FastPredicateContext<'_>>,
7911    ) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
7912        let FastRecognizeTopRequest {
7913            start_state,
7914            stop_state,
7915            start_index,
7916            precedence,
7917            caller_follow_state,
7918        } = request;
7919        // `input.size()` is intentionally only the currently buffered token
7920        // count here. Do not restore an up-front fill just to size this map:
7921        // a small floor avoids tiny-input churn, and larger inputs reserve from
7922        // the buffered token count without forcing startup tokenization. The
7923        // 8x multiplier matches the empirical
7924        // memo-insert / token ratio on heavy grammars (C# averages ~6× and
7925        // Kotlin ~12× memo entries per token), so the table avoids one
7926        // rehash on the typical hot path.
7927        let memo_capacity = fast_recognize_memo_capacity(self.input.size());
7928        let mut recognize_scratch = std::mem::take(&mut self.fast_recognize_scratch);
7929        recognize_scratch.prepare(memo_capacity);
7930        let mut expected = ExpectedTokens::default();
7931        let empty_recovery = self.empty_recovery_symbols();
7932        let outcomes = self.recognize_state_fast(
7933            atn,
7934            FastRecognizeRequest {
7935                state_number: start_state,
7936                stop_state,
7937                index: start_index,
7938                rule_start_index: start_index,
7939                decision_start_index: None,
7940                precedence,
7941                depth: 0,
7942                recovery_symbols: empty_recovery,
7943                recovery_state: None,
7944            },
7945            FastRecognizeScratch {
7946                predicate_context,
7947                visiting: &mut recognize_scratch.visiting,
7948                memo: &mut recognize_scratch.memo,
7949                expected: &mut expected,
7950                native_depth: 0,
7951            },
7952        );
7953        recognize_scratch.release_oversized_memo();
7954        self.fast_recognize_scratch = recognize_scratch;
7955        #[cfg(feature = "perf-counters")]
7956        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
7957            perf_counters::dump();
7958            perf_counters::reset();
7959        }
7960        let caller_follow =
7961            caller_follow_state.map(|state| self.cached_state_expected_token_set(atn, state));
7962        let selected = {
7963            let arena = &self.recognition_arena;
7964            let input = &mut self.input;
7965            select_best_fast_outcome(
7966                outcomes.into_iter(),
7967                self.prediction_mode,
7968                caller_follow.as_deref(),
7969                |index| caller_follow_token_info_for_stream(input, index),
7970                arena,
7971            )
7972        };
7973        match selected {
7974            Some(mut outcome) => {
7975                let alt_number = if self.build_parse_trees || self.fast_track_alt_numbers {
7976                    self.materialize_fast_outcome_nodes(&mut outcome)
7977                } else {
7978                    0
7979                };
7980                Ok((outcome, expected, alt_number))
7981            }
7982            None => Err(expected),
7983        }
7984    }
7985
7986    /// Converts one speculative arena record into the flat public CST.
7987    fn arena_recognized_node_tree(
7988        &mut self,
7989        node_id: RecognizedNodeId,
7990        track_alt_numbers: bool,
7991        track_context_alt_numbers: bool,
7992    ) -> Result<ParseTree, AntlrError> {
7993        let node = self.recognition_arena.node(node_id);
7994        match node {
7995            ArenaRecognizedNode::Token { token } => Ok(self.terminal_tree(token)),
7996            ArenaRecognizedNode::ErrorToken { token } => Ok(self.error_tree(token)),
7997            ArenaRecognizedNode::MissingToken { extra } => {
7998                let (token_type, at_index, text) = match self.recognition_arena.extra(extra) {
7999                    RecognitionExtra::MissingToken {
8000                        token_type,
8001                        at_index,
8002                        text,
8003                    } => (*token_type, *at_index as usize, text.clone()),
8004                    RecognitionExtra::ReturnValues(_) | RecognitionExtra::Diagnostic(_) => {
8005                        unreachable!("missing-token node must reference missing-token extra")
8006                    }
8007                };
8008                let (line, column) = self
8009                    .token_at(at_index)
8010                    .map_or((0, 0), |token| (token.line(), token.column()));
8011                let token = self.insert_synthetic_token(token_type, text, line, column)?;
8012                Ok(self.error_tree(token))
8013            }
8014            ArenaRecognizedNode::Rule {
8015                rule_index,
8016                invoking_state,
8017                alt_number,
8018                start_index,
8019                stop_index,
8020                return_values,
8021                children,
8022            } => {
8023                let mut context = ParserRuleContext::with_child_capacity(
8024                    rule_index as usize,
8025                    invoking_state as isize,
8026                    self.recognition_arena.sequence_len(children),
8027                );
8028                if track_alt_numbers {
8029                    context.set_alt_number((alt_number as usize).max(1));
8030                }
8031                if track_context_alt_numbers {
8032                    context.set_context_alt_number(alt_number as usize);
8033                }
8034                if let Some(extra) = return_values {
8035                    let RecognitionExtra::ReturnValues(values) =
8036                        self.recognition_arena.extra(extra)
8037                    else {
8038                        unreachable!("rule node must reference return-values extra");
8039                    };
8040                    for (name, value) in values {
8041                        context.set_int_return(name.clone(), *value);
8042                    }
8043                }
8044                if let Some(token) = self.token_id_at(start_index as usize) {
8045                    self.set_context_start(&mut context, token);
8046                }
8047                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
8048                    self.set_context_stop(&mut context, token);
8049                }
8050                let mut cursor = self
8051                    .recognition_arena
8052                    .fold_left_recursive_boundaries(children);
8053                while let Some(link) = self.recognition_arena.link(cursor) {
8054                    let child = self.arena_recognized_node_tree(
8055                        link.head,
8056                        track_alt_numbers,
8057                        track_context_alt_numbers,
8058                    )?;
8059                    self.tree.add_child(&mut context, child);
8060                    cursor = link.tail;
8061                }
8062                Ok(self.rule_node(context))
8063            }
8064            ArenaRecognizedNode::LeftRecursiveBoundary { rule_index, .. } => {
8065                Err(AntlrError::Unsupported(format!(
8066                    "unfolded left-recursive boundary for rule {rule_index}"
8067                )))
8068            }
8069        }
8070    }
8071
8072    fn arena_recognized_node_tree_with_implicit_tokens(
8073        &mut self,
8074        node_id: RecognizedNodeId,
8075        alt_tracking: AltNumberTracking,
8076    ) -> Result<ParseTree, AntlrError> {
8077        let node = self.recognition_arena.node(node_id);
8078        match node {
8079            ArenaRecognizedNode::Rule {
8080                rule_index,
8081                invoking_state,
8082                alt_number,
8083                start_index,
8084                stop_index,
8085                children,
8086                ..
8087            } => {
8088                let mut context = ParserRuleContext::with_child_capacity(
8089                    rule_index as usize,
8090                    invoking_state as isize,
8091                    self.recognition_arena.sequence_len(children),
8092                );
8093                if alt_tracking.public {
8094                    context.set_alt_number((alt_number as usize).max(1));
8095                }
8096                if alt_tracking.context {
8097                    context.set_context_alt_number(alt_number as usize);
8098                }
8099                if let Some(token) = self.token_id_at(start_index as usize) {
8100                    self.set_context_start(&mut context, token);
8101                }
8102                if let Some(token) = stop_index.and_then(|index| self.token_id_at(index as usize)) {
8103                    self.set_context_stop(&mut context, token);
8104                }
8105                let children = self
8106                    .recognition_arena
8107                    .fold_left_recursive_boundaries(children);
8108                self.add_arena_implicit_token_children(
8109                    &mut context,
8110                    start_index as usize,
8111                    stop_index.map(|index| index as usize),
8112                    children,
8113                    alt_tracking,
8114                )?;
8115                Ok(self.rule_node(context))
8116            }
8117            _ => {
8118                self.arena_recognized_node_tree(node_id, alt_tracking.public, alt_tracking.context)
8119            }
8120        }
8121    }
8122
8123    fn add_arena_implicit_token_children(
8124        &mut self,
8125        context: &mut ParserRuleContext,
8126        start_index: usize,
8127        stop_index: Option<usize>,
8128        mut children: NodeSeqId,
8129        alt_tracking: AltNumberTracking,
8130    ) -> Result<(), AntlrError> {
8131        let mut cursor = Some(start_index);
8132        while let Some(link) = self.recognition_arena.link(children) {
8133            if let Some((child_start, child_stop)) = self.recognition_arena.node_span(link.head) {
8134                self.add_visible_terminals_before(context, &mut cursor, child_start)?;
8135                let child =
8136                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
8137                self.tree.add_child(context, child);
8138                if let Some(child_stop) = child_stop {
8139                    let next = self.next_visible_after_token(child_stop);
8140                    cursor = match (cursor, next) {
8141                        (None, _) | (_, None) => None,
8142                        (Some(current), Some(next)) => Some(current.max(next)),
8143                    };
8144                }
8145            } else {
8146                let child =
8147                    self.arena_recognized_node_tree_with_implicit_tokens(link.head, alt_tracking)?;
8148                self.tree.add_child(context, child);
8149            }
8150            children = link.tail;
8151        }
8152        if let Some(stop) = stop_index {
8153            self.add_visible_terminals_through(context, cursor, stop)?;
8154        }
8155        Ok(())
8156    }
8157
8158    fn add_visible_terminals_before(
8159        &mut self,
8160        context: &mut ParserRuleContext,
8161        cursor: &mut Option<usize>,
8162        before: usize,
8163    ) -> Result<(), AntlrError> {
8164        let Some(stop) = before.checked_sub(1) else {
8165            return Ok(());
8166        };
8167        let next = self.add_visible_terminals_through(context, *cursor, stop)?;
8168        *cursor = next;
8169        Ok(())
8170    }
8171
8172    fn add_visible_terminals_through(
8173        &mut self,
8174        context: &mut ParserRuleContext,
8175        mut cursor: Option<usize>,
8176        stop: usize,
8177    ) -> Result<Option<usize>, AntlrError> {
8178        while let Some(index) = cursor {
8179            if index > stop {
8180                return Ok(Some(index));
8181            }
8182            let token = self
8183                .input
8184                .get_id(index)
8185                .ok_or_else(|| AntlrError::ParserError {
8186                    line: 0,
8187                    column: 0,
8188                    message: format!("missing token at index {index}"),
8189                    offending: None,
8190                })?;
8191            let is_eof = self.token_type_for_id(token) == TOKEN_EOF;
8192            let child = self.terminal_tree(token);
8193            self.tree.add_child(context, child);
8194            if is_eof {
8195                return Ok(None);
8196            }
8197            cursor = self.next_visible_after_token(index);
8198        }
8199        Ok(None)
8200    }
8201
8202    fn next_visible_after_token(&mut self, index: usize) -> Option<usize> {
8203        let next = self.input.next_visible_after(index);
8204        (next != index).then_some(next)
8205    }
8206
8207    /// Parses a generated rule and returns semantic actions reached on the
8208    /// selected ATN path.
8209    ///
8210    /// This slower path preserves action ordering and token intervals for
8211    /// generated code that replays target-specific action templates after the
8212    /// recognizer has chosen one viable parse path.
8213    pub fn parse_atn_rule_with_actions(
8214        &mut self,
8215        atn: &Atn,
8216        rule_index: usize,
8217    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8218        self.parse_atn_rule_with_action_options(atn, rule_index, &[], false)
8219    }
8220
8221    /// Parses a generated rule and emits ATN actions plus selected rule-init
8222    /// actions reached on the chosen path.
8223    ///
8224    /// Generated parsers use this when a grammar contains rule-level `@init`
8225    /// templates that must run for nested rule invocations. The runtime keeps
8226    /// the action list path-sensitive, so init templates are replayed only for
8227    /// rules that were actually entered by the selected parse.
8228    pub fn parse_atn_rule_with_action_inits(
8229        &mut self,
8230        atn: &Atn,
8231        rule_index: usize,
8232        init_action_rules: &[usize],
8233    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8234        self.parse_atn_rule_with_action_options(atn, rule_index, init_action_rules, false)
8235    }
8236
8237    /// Parses a generated rule with optional semantic-action replay features.
8238    ///
8239    /// `track_alt_numbers` is used by grammars that opt into ANTLR's
8240    /// alt-numbered context behavior. It keeps ordinary parse-tree rendering
8241    /// unchanged for grammars that do not request that target template.
8242    pub fn parse_atn_rule_with_action_options(
8243        &mut self,
8244        atn: &Atn,
8245        rule_index: usize,
8246        init_action_rules: &[usize],
8247        track_alt_numbers: bool,
8248    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8249        self.parse_atn_rule_with_runtime_options(
8250            atn,
8251            rule_index,
8252            ParserRuntimeOptions {
8253                init_action_rules,
8254                track_alt_numbers,
8255                ..ParserRuntimeOptions::default()
8256            },
8257        )
8258    }
8259
8260    /// Parses a generated rule with action replay and parser predicate support.
8261    ///
8262    /// `predicates` maps serialized `(rule_index, pred_index)` coordinates to
8263    /// target-template predicate semantics emitted by the generator. Missing
8264    /// entries are treated as true so unsupported predicate-free grammars keep
8265    /// the previous unconditional transition behavior.
8266    pub fn parse_atn_rule_with_runtime_options(
8267        &mut self,
8268        atn: &Atn,
8269        rule_index: usize,
8270        options: ParserRuntimeOptions<'_>,
8271    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8272        self.parse_atn_rule_with_runtime_options_and_precedence(atn, rule_index, 0, options)
8273    }
8274
8275    fn parse_atn_rule_committed_with_runtime_options(
8276        &mut self,
8277        atn: &Atn,
8278        rule_index: usize,
8279        precedence: i32,
8280        options: ParserRuntimeOptions<'_>,
8281    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8282        let top_level_entry = self.is_top_level_entry();
8283        self.unknown_predicate_policy = options.unknown_predicate_policy;
8284        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8285        let prior_unhandled_action_hits = std::mem::take(&mut self.unhandled_action_hits);
8286        self.clear_prediction_diagnostics();
8287        self.reset_per_parse_caches();
8288        self.reset_recognition_arena();
8289
8290        let mut decision_by_state = vec![None; atn.states().len()];
8291        for (decision, state_number) in atn.decision_to_state().iter().enumerate() {
8292            if let Some(slot) = decision_by_state.get_mut(state_number) {
8293                *slot = Some(decision);
8294            }
8295        }
8296        let mut action_index_by_state = FxHashMap::default();
8297        for &(state, index) in options.action_indices {
8298            action_index_by_state.entry(state).or_insert(index);
8299        }
8300        let mut simulator = ParserAtnSimulator::new(atn);
8301        simulator.set_track_prediction_rule_calls(!options.rule_args.is_empty());
8302        let (result, deferred_actions) = {
8303            let mut committed = CommittedAtnParser {
8304                parser: self,
8305                atn,
8306                simulator,
8307                options,
8308                decision_by_state,
8309                action_index_by_state,
8310                deferred_actions: Vec::new(),
8311            };
8312            let result = committed.parse_rule(rule_index, precedence, None, None);
8313            (result, committed.deferred_actions)
8314        };
8315
8316        if top_level_entry {
8317            self.report_generated_parser_diagnostics();
8318        }
8319        let semantic_error = self.unknown_semantic_error();
8320        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8321        self.restore_prior_unhandled_action_hits(prior_unhandled_action_hits);
8322        if top_level_entry && let Some(error) = self.take_parse_abort() {
8323            self.reset_unknown_semantic_hits();
8324            return Err(error);
8325        }
8326        if let Some(error) = semantic_error {
8327            if top_level_entry {
8328                self.reset_unknown_semantic_hits();
8329            }
8330            return Err(error);
8331        }
8332        let result = result.map(|outcome| (outcome.tree, deferred_actions));
8333        if top_level_entry && let Err(error) = &result {
8334            self.report_unrecovered_parser_error(error);
8335        }
8336        result
8337    }
8338
8339    /// Parses a generated rule with action replay, parser predicate support,
8340    /// and an initial left-recursive precedence threshold.
8341    pub fn parse_atn_rule_with_runtime_options_and_precedence(
8342        &mut self,
8343        atn: &Atn,
8344        rule_index: usize,
8345        precedence: i32,
8346        options: ParserRuntimeOptions<'_>,
8347    ) -> Result<(ParseTree, Vec<ParserAction>), AntlrError> {
8348        if !options.action_indices.is_empty() {
8349            return self.parse_atn_rule_committed_with_runtime_options(
8350                atn, rule_index, precedence, options,
8351            );
8352        }
8353        let report_unrecovered_error = self.is_top_level_entry();
8354        let ParserRuntimeOptions {
8355            init_action_rules,
8356            track_alt_numbers,
8357            track_context_alt_numbers,
8358            predicates,
8359            semantics,
8360            rule_args,
8361            member_actions,
8362            return_actions,
8363            unknown_predicate_policy,
8364            ..
8365        } = options;
8366        let capture_alt_numbers = track_alt_numbers || track_context_alt_numbers;
8367        if init_action_rules.is_empty()
8368            && !capture_alt_numbers
8369            && predicates.is_empty()
8370            && semantics.is_none()
8371            && rule_args.is_empty()
8372            && member_actions.is_empty()
8373            && return_actions.is_empty()
8374            && unknown_predicate_policy == UnknownSemanticPolicy::AssumeTrue
8375            && !atn_has_observable_action_transitions(atn)
8376            && !self.semantic_hooks.observes_parser_decisions()
8377            && (!self.semantic_hooks.observes_parser_predicates()
8378                || !atn_has_predicate_transitions(atn))
8379        {
8380            return self
8381                .parse_atn_rule_with_precedence(atn, rule_index, precedence)
8382                .map(|tree| (tree, Vec::new()));
8383        }
8384        if !self.semantic_hooks.observes_parser_decisions()
8385            && can_use_fast_predicate_recognizer(atn, &options)
8386        {
8387            self.unknown_predicate_policy = unknown_predicate_policy;
8388            let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8389            let member_values = self.int_members.clone();
8390            let result = self
8391                .parse_atn_rule_with_precedence_inner(
8392                    atn,
8393                    rule_index,
8394                    precedence,
8395                    Some(FastPredicateContext {
8396                        predicates,
8397                        semantics,
8398                        member_values: &member_values,
8399                    }),
8400                    AltNumberTracking {
8401                        public: track_alt_numbers,
8402                        context: track_context_alt_numbers,
8403                    },
8404                )
8405                .map(|tree| (tree, Vec::new()));
8406            if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
8407                self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8408            }
8409            return result;
8410        }
8411        self.unknown_predicate_policy = unknown_predicate_policy;
8412        // A generated parent may have already recorded unknown-predicate
8413        // coordinates before descending into this (interpreted) child. Clearing
8414        // unconditionally would drop them before the parent's public entry
8415        // surfaces them, so stash and restore around this call: recognition sees
8416        // only the hits it records itself (so the fail-loud check below reflects
8417        // this rule), and the parent's prior hits are merged back afterward.
8418        let prior_unknown_predicate_hits = std::mem::take(&mut self.unknown_predicate_hits);
8419        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
8420            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
8421        })?;
8422        let stop_state = atn
8423            .rule_to_stop_state()
8424            .get(rule_index)
8425            .filter(|state| *state != usize::MAX)
8426            .ok_or_else(|| {
8427                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
8428            })?;
8429
8430        let start_index = self.current_visible_index();
8431        self.clear_prediction_diagnostics();
8432        self.reset_per_parse_caches();
8433        self.reset_recognition_arena();
8434        let init_action_rules = init_action_rules.iter().copied().collect::<BTreeSet<_>>();
8435        let invoking_state = self.pending_invoking_states.pop();
8436        let local_int_arg = invoking_state
8437            .and_then(|state| usize::try_from(state).ok())
8438            .and_then(|state| rule_local_int_arg(rule_args, state, rule_index, None));
8439        let mut visiting = BTreeSet::new();
8440        let mut memo = BTreeMap::new();
8441        let mut expected = ExpectedTokens::default();
8442        let member_values = self.int_members.clone();
8443        let return_values = BTreeMap::new();
8444        let outcomes = self.recognize_state(
8445            atn,
8446            RecognizeRequest {
8447                state_number: start_state,
8448                stop_state,
8449                index: start_index,
8450                rule_start_index: start_index,
8451                decision_start_index: None,
8452                init_action_rules: &init_action_rules,
8453                predicates,
8454                semantics,
8455                rule_args,
8456                member_actions,
8457                return_actions,
8458                local_int_arg,
8459                member_values,
8460                return_values,
8461                rule_alt_number: 0,
8462                track_alt_numbers: capture_alt_numbers,
8463                consumed_eof: false,
8464                committed_decision: false,
8465                precedence,
8466                depth: 0,
8467                recovery_symbols: BTreeSet::new(),
8468                recovery_state: None,
8469            },
8470            &mut visiting,
8471            &mut memo,
8472            &mut expected,
8473        );
8474        if let Some(error) = self.unknown_semantic_error() {
8475            self.report_token_source_errors();
8476            // Keep the recorded coordinates: when this interpreted rule is a
8477            // child of a generated parent, the parent's catch block recovers an
8478            // ordinary `AntlrError` into a partial subtree, so the fail-loud
8479            // coordinate must survive on the parser for the top-level entry's
8480            // `take_unknown_semantic_error` to surface it. Cross-parse staleness
8481            // is handled by clearing at the top-level generated entry instead.
8482            return Err(error);
8483        }
8484        // Recognition recorded no unresolved coordinate of its own; merge the
8485        // parent's prior hits back so its public entry can still surface them.
8486        self.restore_prior_unknown_predicate_hits(prior_unknown_predicate_hits);
8487        let Some(outcome) = select_best_outcome(
8488            outcomes.into_iter(),
8489            self.prediction_mode,
8490            &self.recognition_arena,
8491        ) else {
8492            let error = self.recognition_error(rule_index, start_index, &expected);
8493            self.record_syntax_errors(1);
8494            self.report_token_source_errors();
8495            if report_unrecovered_error {
8496                self.report_unrecovered_parser_error(&error);
8497            }
8498            return Err(error);
8499        };
8500
8501        self.record_syntax_errors(self.recognition_arena.diagnostics_len(outcome.diagnostics));
8502        self.dispatch_parser_diagnostics(&self.prediction_diagnostics);
8503        self.dispatch_parser_diagnostics(self.recognition_arena.diagnostics(outcome.diagnostics));
8504        self.report_token_source_errors();
8505        let mut actions = outcome.actions;
8506        if init_action_rules.contains(&rule_index) {
8507            actions.insert(
8508                0,
8509                ParserAction::new_rule_init(rule_index, start_index, Some(start_state)),
8510            );
8511        }
8512        let mut context =
8513            ParserRuleContext::new(rule_index, invoking_state.unwrap_or_else(|| self.state()));
8514        if track_alt_numbers {
8515            context.set_alt_number(outcome.alt_number.max(1));
8516        }
8517        if track_context_alt_numbers {
8518            context.set_context_alt_number(outcome.alt_number);
8519        }
8520        for (name, value) in outcome.return_values {
8521            context.set_int_return(name, value);
8522        }
8523        if let Some(token) = self.token_id_at(start_index) {
8524            self.set_context_start(&mut context, token);
8525        }
8526        if let Some(token) = self.rule_stop_token_id(outcome.index, outcome.consumed_eof) {
8527            self.set_context_stop(&mut context, token);
8528        }
8529        let live_root = if self.build_parse_trees {
8530            self.recognition_arena
8531                .fold_left_recursive_boundaries(outcome.nodes)
8532        } else {
8533            outcome.nodes
8534        };
8535        if self.build_parse_trees {
8536            let mut nodes = live_root;
8537            while let Some(link) = self.recognition_arena.link(nodes) {
8538                let child = self.arena_recognized_node_tree(
8539                    link.head,
8540                    track_alt_numbers,
8541                    track_context_alt_numbers,
8542                )?;
8543                self.tree.add_child(&mut context, child);
8544                nodes = link.tail;
8545            }
8546        }
8547        self.finish_recognition_arena(live_root, outcome.diagnostics);
8548        self.input.seek(outcome.index);
8549
8550        let tree = self.rule_node(context);
8551        self.release_tree_scratch_if_idle();
8552        Ok((tree, actions))
8553    }
8554
8555    /// Temporary parser entry used by generated parser methods while the parser
8556    /// ATN simulator is being implemented.
8557    ///
8558    /// This keeps generated parser crates buildable and gives us a stable method
8559    /// surface for every grammar rule. It intentionally accepts all remaining
8560    /// tokens into one rule context; it is not the final parser semantics.
8561    pub fn parse_interpreted_rule(&mut self, rule_index: usize) -> Result<ParseTree, AntlrError> {
8562        let mut context = ParserRuleContext::new(rule_index, self.state());
8563        while self.la(1) != TOKEN_EOF {
8564            let token_type = self.la(1);
8565            let child = self.match_token(token_type)?;
8566            if self.build_parse_trees {
8567                self.tree.add_child(&mut context, child);
8568            }
8569        }
8570        if self.build_parse_trees {
8571            let child = self.match_eof()?;
8572            self.tree.add_child(&mut context, child);
8573        }
8574        let tree = self.rule_node(context);
8575        self.release_tree_scratch_if_idle();
8576        Ok(tree)
8577    }
8578
8579    /// Builds the parser error reported when no ATN path can reach the active
8580    /// rule stop state.
8581    fn recognition_error(
8582        &mut self,
8583        rule_index: usize,
8584        start_index: usize,
8585        expected: &ExpectedTokens,
8586    ) -> AntlrError {
8587        let (index, message) = self.expected_error_message(rule_index, start_index, expected);
8588        self.input.seek(index);
8589        let current = self.input.lt(1);
8590        let line = current.as_ref().map(Token::line).unwrap_or_default();
8591        let column = current.as_ref().map(Token::column).unwrap_or_default();
8592        AntlrError::ParserError {
8593            line,
8594            column,
8595            message,
8596            offending: current.as_ref().map(Token::token_id),
8597        }
8598    }
8599
8600    /// Builds the token index and ANTLR-compatible message for a failed rule.
8601    fn expected_error_message(
8602        &mut self,
8603        rule_index: usize,
8604        start_index: usize,
8605        expected: &ExpectedTokens,
8606    ) -> (usize, String) {
8607        let index = expected
8608            .index
8609            .or_else(|| expected.no_viable.map(|no_viable| no_viable.error_index))
8610            .unwrap_or_else(|| self.input.index());
8611        self.input.seek(index);
8612        let current = self.input.lt(1);
8613        let message = if expected
8614            .no_viable
8615            .as_ref()
8616            .is_some_and(|no_viable| no_viable.error_index == index)
8617        {
8618            let start = expected
8619                .no_viable
8620                .as_ref()
8621                .map_or(start_index, |no_viable| no_viable.start_index);
8622            let text = display_input_text(&self.input.text(start, index));
8623            format!("no viable alternative at input '{text}'")
8624        } else if expected.symbols.is_empty() {
8625            if expected.index.is_some() {
8626                let found = current
8627                    .as_ref()
8628                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display);
8629                if current
8630                    .as_ref()
8631                    .is_some_and(|token| token.token_type() == TOKEN_EOF)
8632                {
8633                    format!(
8634                        "missing {} at {found}",
8635                        self.expected_symbols_display(&expected.symbols)
8636                    )
8637                } else {
8638                    format!("mismatched input {found}")
8639                }
8640            } else {
8641                format!("no viable alternative while parsing rule {rule_index}")
8642            }
8643        } else {
8644            format!(
8645                "mismatched input {} expecting {}",
8646                current
8647                    .as_ref()
8648                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8649                self.expected_symbols_display(&expected.symbols)
8650            )
8651        };
8652        (index, message)
8653    }
8654
8655    /// Converts a failed child rule into a recovered outcome so the parent can
8656    /// continue after reporting the child diagnostic.
8657    fn child_rule_failure_recovery(
8658        &mut self,
8659        rule_index: usize,
8660        start_index: usize,
8661        sync_symbols: &BTreeSet<i32>,
8662        member_values: MemberEnv,
8663        expected: &ExpectedTokens,
8664    ) -> Option<RecognizeOutcome> {
8665        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
8666        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
8667        let mut next_index = error_index;
8668        loop {
8669            let symbol = self.token_type_at(next_index);
8670            if sync_symbols.contains(&symbol) {
8671                if next_index == error_index {
8672                    return None;
8673                }
8674                break;
8675            }
8676            if symbol == TOKEN_EOF {
8677                break;
8678            }
8679            let after = self.consume_index(next_index, symbol);
8680            if after == next_index {
8681                break;
8682            }
8683            next_index = after;
8684        }
8685        let mut nodes = NodeSeqId::EMPTY;
8686        let error = self.arena_token_node(error_index, true);
8687        self.arena_prepend(&mut nodes, error);
8688        let diagnostics = self
8689            .recognition_arena
8690            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
8691        Some(RecognizeOutcome {
8692            index: next_index,
8693            consumed_eof: false,
8694            alt_number: 0,
8695            member_values,
8696            return_values: BTreeMap::new(),
8697            diagnostics,
8698            decisions: Vec::new(),
8699            actions: Vec::new(),
8700            nodes,
8701        })
8702    }
8703
8704    /// Adapts the optional recovery result to the normal outcome list used by
8705    /// rule-call transitions.
8706    fn child_rule_failure_recovery_outcomes(
8707        &mut self,
8708        request: ChildRuleFailureRecovery<'_>,
8709    ) -> Vec<RecognizeOutcome> {
8710        let sync_symbols =
8711            state_sync_symbols(request.atn, request.follow_state, request.stop_state);
8712        self.child_rule_failure_recovery(
8713            request.rule_index,
8714            request.start_index,
8715            &sync_symbols,
8716            request.member_values,
8717            request.expected,
8718        )
8719        .into_iter()
8720        .collect()
8721    }
8722
8723    /// Formats expected token types using ANTLR's single-token or set syntax.
8724    fn expected_symbols_display(&self, symbols: &BTreeSet<i32>) -> String {
8725        expected_symbols_display(symbols, self.vocabulary())
8726    }
8727
8728    /// Returns the single-token deletion repair if the token after `index`
8729    /// satisfies the failed consuming transition.
8730    fn single_token_deletion(
8731        &mut self,
8732        transition: ParserTransition<'_>,
8733        index: usize,
8734        max_token_type: i32,
8735        expected_symbols: &BTreeSet<i32>,
8736    ) -> Option<(ParserDiagnostic, usize, i32)> {
8737        let current_symbol = self.token_type_at(index);
8738        if current_symbol == TOKEN_EOF {
8739            return None;
8740        }
8741        let next_index = self.consume_index(index, current_symbol);
8742        if next_index == index {
8743            return None;
8744        }
8745        let next_symbol = self.token_type_at(next_index);
8746        if !transition.matches(next_symbol, 1, max_token_type) {
8747            return None;
8748        }
8749        let transition_expected = transition_expected_symbols(transition, max_token_type);
8750        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8751            &transition_expected
8752        } else {
8753            expected_symbols
8754        });
8755        let current = self.token_at(index);
8756        let message = format!(
8757            "extraneous input {} expecting {expected_display}",
8758            current
8759                .as_ref()
8760                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8761        );
8762        Some((
8763            diagnostic_for_token(current, message),
8764            next_index,
8765            next_symbol,
8766        ))
8767    }
8768
8769    /// Returns the repair used when deleting the current token lets a recovery
8770    /// state continue with the following token.
8771    fn current_token_deletion(
8772        &mut self,
8773        index: usize,
8774        expected_symbols: &BTreeSet<i32>,
8775    ) -> Option<(ParserDiagnostic, usize, Vec<usize>)> {
8776        if expected_symbols.is_empty() {
8777            return None;
8778        }
8779        let current_symbol = self.token_type_at(index);
8780        if current_symbol == TOKEN_EOF {
8781            return None;
8782        }
8783        let current = self.token_at(index);
8784        let message = format!(
8785            "extraneous input {} expecting {}",
8786            current
8787                .as_ref()
8788                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
8789            self.expected_symbols_display(expected_symbols)
8790        );
8791        let diagnostic = diagnostic_for_token(current, message);
8792        let mut skipped = Vec::new();
8793        let mut cursor = index;
8794        loop {
8795            let symbol = self.token_type_at(cursor);
8796            if symbol == TOKEN_EOF {
8797                return None;
8798            }
8799            skipped.push(cursor);
8800            let next_index = self.consume_index(cursor, symbol);
8801            if next_index == cursor {
8802                return None;
8803            }
8804            let next_symbol = self.token_type_at(next_index);
8805            if expected_symbols.contains(&next_symbol) {
8806                return Some((diagnostic, next_index, skipped));
8807            }
8808            cursor = next_index;
8809        }
8810    }
8811
8812    /// Returns the single-token insertion repair for a failed consuming
8813    /// transition. The caller validates the repair by continuing from the
8814    /// transition target at the same input index.
8815    fn single_token_insertion(
8816        &mut self,
8817        transition: ParserTransition<'_>,
8818        index: usize,
8819        max_token_type: i32,
8820        expected_symbols: &BTreeSet<i32>,
8821        follow_symbols: &BTreeSet<i32>,
8822    ) -> Option<(ParserDiagnostic, i32, String)> {
8823        let current_symbol = self.token_type_at(index);
8824        if !follow_symbols.contains(&current_symbol) {
8825            return None;
8826        }
8827        let transition_expected = transition_expected_symbols(transition, max_token_type);
8828        let token_type = transition_expected.iter().next().copied()?;
8829        let expected_display = self.expected_symbols_display(if expected_symbols.is_empty() {
8830            &transition_expected
8831        } else {
8832            expected_symbols
8833        });
8834        let mut token_symbols = BTreeSet::new();
8835        token_symbols.insert(token_type);
8836        let missing_token_display = self.expected_symbols_display(&token_symbols);
8837        let current = self.token_at(index);
8838        let message = format!(
8839            "missing {expected_display} at {}",
8840            current
8841                .as_ref()
8842                .map_or_else(|| "'<EOF>'".to_owned(), token_input_display)
8843        );
8844        let text = format!("<missing {missing_token_display}>");
8845        Some((
8846            diagnostic_for_token(current.as_ref(), message),
8847            token_type,
8848            text,
8849        ))
8850    }
8851
8852    /// Explores ANTLR's single-token deletion recovery for the fast recognizer:
8853    /// skip the unexpected current token when the following token satisfies the
8854    /// transition that failed.
8855    fn fast_single_token_deletion_recovery(
8856        &mut self,
8857        recovery: FastRecoveryRequest<'_, '_>,
8858        predicate_context: Option<FastPredicateContext<'_>>,
8859    ) -> Vec<FastRecognizeOutcome> {
8860        let FastRecoveryRequest {
8861            atn,
8862            transition,
8863            expected_symbols,
8864            target,
8865            request,
8866            visiting,
8867            memo,
8868            expected,
8869        } = recovery;
8870        let FastRecognizeRequest {
8871            stop_state,
8872            index,
8873            rule_start_index,
8874            decision_start_index,
8875            precedence,
8876            depth,
8877            ..
8878        } = request;
8879        let Some((diagnostic, next_index, next_symbol)) =
8880            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
8881        else {
8882            return Vec::new();
8883        };
8884        let after_next = self.consume_index(next_index, next_symbol);
8885        let empty_recovery = self.empty_recovery_symbols();
8886        self.recognize_state_fast(
8887            atn,
8888            FastRecognizeRequest {
8889                state_number: target,
8890                stop_state,
8891                index: after_next,
8892                rule_start_index,
8893                decision_start_index,
8894                precedence,
8895                depth: depth + 1,
8896                recovery_symbols: empty_recovery,
8897                recovery_state: None,
8898            },
8899            FastRecognizeScratch {
8900                predicate_context,
8901                visiting,
8902                memo,
8903                expected,
8904                native_depth: 0,
8905            },
8906        )
8907        .into_iter()
8908        .map(|mut outcome| {
8909            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
8910            outcome.diagnostics = self
8911                .recognition_arena
8912                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8913            if self.fast_token_nodes_enabled {
8914                let token = self.arena_token_node(next_index, false);
8915                self.defer_fast_outcome_node(&mut outcome, token);
8916                let error = self.arena_token_node(index, true);
8917                self.defer_fast_outcome_node(&mut outcome, error);
8918            }
8919            outcome
8920        })
8921        .collect()
8922    }
8923
8924    /// Explores ANTLR's single-token insertion recovery for the fast recognizer:
8925    /// pretend the expected transition token was present and continue without
8926    /// consuming the current token.
8927    fn fast_single_token_insertion_recovery(
8928        &mut self,
8929        recovery: FastRecoveryRequest<'_, '_>,
8930        predicate_context: Option<FastPredicateContext<'_>>,
8931    ) -> Vec<FastRecognizeOutcome> {
8932        let FastRecoveryRequest {
8933            atn,
8934            transition,
8935            expected_symbols,
8936            target,
8937            request,
8938            visiting,
8939            memo,
8940            expected,
8941        } = recovery;
8942        let FastRecognizeRequest {
8943            stop_state,
8944            index,
8945            rule_start_index,
8946            decision_start_index,
8947            precedence,
8948            depth,
8949            ..
8950        } = request;
8951        let follow_symbols = self.cached_state_expected_symbols(atn, transition.target());
8952        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
8953            transition,
8954            index,
8955            atn.max_token_type(),
8956            &expected_symbols,
8957            &follow_symbols,
8958        ) else {
8959            return Vec::new();
8960        };
8961        let empty_recovery = self.empty_recovery_symbols();
8962        self.recognize_state_fast(
8963            atn,
8964            FastRecognizeRequest {
8965                state_number: target,
8966                stop_state,
8967                index,
8968                rule_start_index,
8969                decision_start_index,
8970                precedence,
8971                depth: depth + 1,
8972                recovery_symbols: empty_recovery,
8973                recovery_state: None,
8974            },
8975            FastRecognizeScratch {
8976                predicate_context,
8977                visiting,
8978                memo,
8979                expected,
8980                native_depth: 0,
8981            },
8982        )
8983        .into_iter()
8984        .map(|mut outcome| {
8985            outcome.diagnostics = self
8986                .recognition_arena
8987                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
8988            let missing = self.arena_missing_token_node(token_type, index, text.clone());
8989            self.defer_fast_outcome_node(&mut outcome, missing);
8990            outcome
8991        })
8992        .collect()
8993    }
8994
8995    /// Retries the current fast-recognition state after deleting one
8996    /// unexpected token that precedes a valid loop or block continuation.
8997    fn fast_current_token_deletion_recovery(
8998        &mut self,
8999        recovery: FastCurrentTokenDeletionRequest<'_, '_>,
9000        predicate_context: Option<FastPredicateContext<'_>>,
9001    ) -> Vec<FastRecognizeOutcome> {
9002        let FastCurrentTokenDeletionRequest {
9003            atn,
9004            expected_symbols,
9005            mut request,
9006            visiting,
9007            memo,
9008            expected,
9009        } = recovery;
9010        if request.index == request.rule_start_index {
9011            return Vec::new();
9012        }
9013        let Some((diagnostic, next_index, skipped)) =
9014            self.current_token_deletion(request.index, &expected_symbols)
9015        else {
9016            return Vec::new();
9017        };
9018        request.state_number = request.recovery_state.unwrap_or(request.state_number);
9019        request.index = next_index;
9020        request.depth += 1;
9021        request.recovery_state = None;
9022        self.recognize_state_fast(
9023            atn,
9024            request,
9025            FastRecognizeScratch {
9026                predicate_context,
9027                visiting,
9028                memo,
9029                expected,
9030                native_depth: 0,
9031            },
9032        )
9033        .into_iter()
9034        .map(|mut outcome| {
9035            outcome.diagnostics = self
9036                .recognition_arena
9037                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
9038            for index in skipped.iter().rev() {
9039                let error = self.arena_token_node(*index, true);
9040                self.defer_fast_outcome_node(&mut outcome, error);
9041            }
9042            outcome
9043        })
9044        .collect()
9045    }
9046
9047    /// Converts a failed child rule into a recovered fast-recognizer outcome so
9048    /// the parent can keep its child rule context and continue at a sync token.
9049    fn fast_child_rule_failure_recovery(
9050        &mut self,
9051        rule_index: usize,
9052        start_index: usize,
9053        sync_symbols: &BTreeSet<i32>,
9054        expected: &ExpectedTokens,
9055    ) -> Option<FastRecognizeOutcome> {
9056        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
9057        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
9058        let mut next_index = error_index;
9059        loop {
9060            let symbol = self.token_type_at(next_index);
9061            if sync_symbols.contains(&symbol) {
9062                if next_index == error_index {
9063                    return None;
9064                }
9065                break;
9066            }
9067            if symbol == TOKEN_EOF {
9068                break;
9069            }
9070            let after = self.consume_index(next_index, symbol);
9071            if after == next_index {
9072                break;
9073            }
9074            next_index = after;
9075        }
9076        let diagnostics = self
9077            .recognition_arena
9078            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
9079        let mut nodes = NodeSeqId::EMPTY;
9080        if self.fast_token_nodes_enabled {
9081            let error = self.arena_token_node(error_index, true);
9082            self.arena_prepend(&mut nodes, error);
9083        }
9084        Some(FastRecognizeOutcome {
9085            index: next_index,
9086            consumed_eof: false,
9087            diagnostics,
9088            deferred_nodes: FastDeferredNodeId::EMPTY,
9089            nodes,
9090        })
9091    }
9092
9093    /// Adapts the optional child-rule recovery result to the fast-recognizer
9094    /// outcome list used by rule-call transitions.
9095    fn fast_child_rule_failure_recovery_outcomes(
9096        &mut self,
9097        request: FastChildRuleFailureRecoveryRequest<'_>,
9098    ) -> Vec<FastRecognizeOutcome> {
9099        let FastChildRuleFailureRecoveryRequest {
9100            atn,
9101            rule_index,
9102            start_index,
9103            follow_state,
9104            stop_state,
9105            expected,
9106        } = request;
9107        let sync_symbols = state_sync_symbols(atn, follow_state, stop_state);
9108        self.fast_child_rule_failure_recovery(rule_index, start_index, &sync_symbols, expected)
9109            .into_iter()
9110            .collect()
9111    }
9112
9113    fn defer_fast_outcome_node(
9114        &mut self,
9115        outcome: &mut FastRecognizeOutcome,
9116        node: RecognizedNodeId,
9117    ) {
9118        if outcome.deferred_nodes.is_empty() {
9119            self.arena_prepend(&mut outcome.nodes, node);
9120            return;
9121        }
9122        let fragment = self.recognition_arena.prepend(NodeSeqId::EMPTY, node);
9123        let fragment = self.recognition_arena.deferred_fragment(fragment);
9124        outcome.deferred_nodes = self
9125            .recognition_arena
9126            .concat_deferred_nodes(fragment, outcome.deferred_nodes);
9127    }
9128
9129    fn defer_fast_outcome_alternative(
9130        &mut self,
9131        outcome: &mut FastRecognizeOutcome,
9132        alt_number: usize,
9133    ) {
9134        let alternative = self.recognition_arena.deferred_alternative(alt_number);
9135        outcome.deferred_nodes = self
9136            .recognition_arena
9137            .concat_deferred_nodes(alternative, outcome.deferred_nodes);
9138    }
9139
9140    fn defer_fast_outcome_boundary(
9141        &mut self,
9142        outcome: &mut FastRecognizeOutcome,
9143        rule_index: usize,
9144    ) {
9145        let boundary = self
9146            .recognition_arena
9147            .deferred_left_recursive_boundary(rule_index);
9148        outcome.deferred_nodes = self
9149            .recognition_arena
9150            .concat_deferred_nodes(boundary, outcome.deferred_nodes);
9151    }
9152
9153    fn materialize_fast_deferred_nodes(
9154        &mut self,
9155        root: FastDeferredNodeId,
9156        initial_suffix: NodeSeqId,
9157    ) -> (NodeSeqId, usize) {
9158        if root.is_empty() {
9159            return (initial_suffix, 0);
9160        }
9161
9162        enum Frame {
9163            Visit(FastDeferredNodeId),
9164            ContinuePrefix(FastDeferredNodeId),
9165            FinishRule {
9166                rule: FastDeferredRule,
9167                parent_suffix: NodeSeqId,
9168                parent_alt_number: u32,
9169                parent_pending_boundary: Option<RecognizedNodeId>,
9170            },
9171        }
9172
9173        let mut result = initial_suffix;
9174        // The rope is visited suffix-first while nodes are prepended. Later
9175        // alternatives arrive first, so earlier markers overwrite them; a
9176        // boundary redirects those earlier markers to the wrapped context.
9177        let mut alt_number = 0;
9178        let mut pending_boundary = None;
9179        let mut pending = Vec::with_capacity(16);
9180        pending.push(Frame::Visit(root));
9181        let mut fragment_nodes = Vec::new();
9182        while let Some(frame) = pending.pop() {
9183            match frame {
9184                Frame::Visit(deferred) => {
9185                    if deferred.is_empty() {
9186                        continue;
9187                    }
9188
9189                    match self.recognition_arena.deferred_node(deferred) {
9190                        FastDeferredNode::Fragment(sequence) => {
9191                            fragment_nodes.clear();
9192                            fragment_nodes.extend(self.recognition_arena.iter(sequence));
9193                            while let Some(node) = fragment_nodes.pop() {
9194                                self.arena_prepend(&mut result, node);
9195                            }
9196                        }
9197                        FastDeferredNode::Rule(rule) => {
9198                            let rule = self.recognition_arena.deferred_rule(rule);
9199                            let parent_suffix = result;
9200                            let parent_alt_number = alt_number;
9201                            let parent_pending_boundary = pending_boundary;
9202                            result = rule.children;
9203                            alt_number = 0;
9204                            pending_boundary = None;
9205                            pending.push(Frame::FinishRule {
9206                                rule,
9207                                parent_suffix,
9208                                parent_alt_number,
9209                                parent_pending_boundary,
9210                            });
9211                            pending.push(Frame::Visit(rule.deferred_children));
9212                        }
9213                        FastDeferredNode::Alternative(selected) => {
9214                            if let Some(boundary) = pending_boundary {
9215                                self.recognition_arena
9216                                    .set_boundary_alt_number(boundary, selected);
9217                            } else {
9218                                alt_number = selected;
9219                            }
9220                        }
9221                        FastDeferredNode::LeftRecursiveBoundary { rule_index } => {
9222                            let boundary = self.arena_boundary_node(rule_index as usize, 0);
9223                            self.arena_prepend(&mut result, boundary);
9224                            pending_boundary = Some(boundary);
9225                        }
9226                        FastDeferredNode::Concat {
9227                            prefix,
9228                            suffix: deferred_suffix,
9229                        } => {
9230                            pending.push(Frame::ContinuePrefix(prefix));
9231                            pending.push(Frame::Visit(deferred_suffix));
9232                        }
9233                    }
9234                }
9235                Frame::ContinuePrefix(prefix) => pending.push(Frame::Visit(prefix)),
9236                Frame::FinishRule {
9237                    rule,
9238                    parent_suffix,
9239                    parent_alt_number,
9240                    parent_pending_boundary,
9241                } => {
9242                    let node = self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
9243                        rule_index: rule.rule_index,
9244                        invoking_state: rule.invoking_state,
9245                        alt_number,
9246                        start_index: rule.start_index,
9247                        stop_index: rule.stop_index,
9248                        return_values: None,
9249                        children: result,
9250                    });
9251                    result = parent_suffix;
9252                    self.arena_prepend(&mut result, node);
9253                    alt_number = parent_alt_number;
9254                    pending_boundary = parent_pending_boundary;
9255                }
9256            }
9257        }
9258        (result, alt_number as usize)
9259    }
9260
9261    fn materialize_fast_outcome_nodes(&mut self, outcome: &mut FastRecognizeOutcome) -> usize {
9262        let deferred_nodes = std::mem::take(&mut outcome.deferred_nodes);
9263        let (nodes, alt_number) =
9264            self.materialize_fast_deferred_nodes(deferred_nodes, outcome.nodes);
9265        outcome.nodes = nodes;
9266        alt_number
9267    }
9268
9269    /// Walks one ordinary `*`/`+` repetition at a time so input length grows
9270    /// heap work instead of the native call stack.
9271    fn recognize_repetition_fast(
9272        &mut self,
9273        atn: &Atn,
9274        request: &FastRecognizeRequest,
9275        shape: FastRepetitionShape,
9276        scratch: FastRecognizeScratch<'_, '_>,
9277    ) -> Vec<FastRecognizeOutcome> {
9278        let FastRecognizeScratch {
9279            predicate_context,
9280            visiting,
9281            memo,
9282            expected,
9283            native_depth,
9284        } = scratch;
9285        let lookahead = if self.fast_first_set_prefilter {
9286            atn.state(request.state_number).and_then(|state| {
9287                state
9288                    .rule_index()
9289                    .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9290                    .map(|rule_stop| self.cached_decision_lookahead(atn, state, rule_stop))
9291            })
9292        } else {
9293            None
9294        };
9295        let (enter_alt_number, exit_alt_number) = if self.fast_track_alt_numbers {
9296            let state = atn
9297                .state(request.state_number)
9298                .expect("repetition request state must exist");
9299            (
9300                next_alt_number(state, 2, shape.enter_transition_index, 0, true),
9301                next_alt_number(state, 2, shape.exit_transition_index, 0, true),
9302            )
9303        } else {
9304            (0, 0)
9305        };
9306        let mut work = Vec::with_capacity(2);
9307        push_fast_repetition_work(
9308            &mut work,
9309            shape,
9310            FastRepetitionPath {
9311                index: request.index,
9312                deferred_nodes: FastDeferredNodeId::EMPTY,
9313                diagnostics: DiagnosticSeqId::EMPTY,
9314                consumed_eof: false,
9315            },
9316            lookahead.as_deref(),
9317            self.token_type_at(request.index),
9318        );
9319        let mut coordinates = FastRepetitionCoordinates::new(request.index);
9320        let mut outcomes = Vec::new();
9321        while let Some(item) = work.pop() {
9322            match item {
9323                FastRepetitionWork::Enter(path) => {
9324                    if !coordinates.insert_entered(path) {
9325                        continue;
9326                    }
9327                    let path_nodes = if enter_alt_number == 0 {
9328                        path.deferred_nodes
9329                    } else {
9330                        let alternative = self
9331                            .recognition_arena
9332                            .deferred_alternative(enter_alt_number);
9333                        self.recognition_arena
9334                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9335                    };
9336                    let body_outcomes = self.recognize_state_fast(
9337                        atn,
9338                        FastRecognizeRequest {
9339                            state_number: shape.enter_target,
9340                            stop_state: shape.body_stop_state,
9341                            index: path.index,
9342                            rule_start_index: request.rule_start_index,
9343                            decision_start_index: request.decision_start_index,
9344                            precedence: request.precedence,
9345                            depth: request.depth.saturating_add(1),
9346                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9347                            recovery_state: request.recovery_state,
9348                        },
9349                        FastRecognizeScratch {
9350                            predicate_context,
9351                            visiting: &mut *visiting,
9352                            memo: &mut *memo,
9353                            expected: &mut *expected,
9354                            native_depth: native_depth + 1,
9355                        },
9356                    );
9357                    for body in body_outcomes.into_iter().rev() {
9358                        // ANTLR rejects nullable repetition bodies. Keep the
9359                        // interpreter bounded for malformed or recovered ATNs
9360                        // by mirroring the existing same-coordinate cycle cut.
9361                        if body.index <= path.index {
9362                            continue;
9363                        }
9364                        let body_fragment = self.recognition_arena.deferred_fragment(body.nodes);
9365                        let body_nodes = self
9366                            .recognition_arena
9367                            .concat_deferred_nodes(body.deferred_nodes, body_fragment);
9368                        let deferred_nodes = self
9369                            .recognition_arena
9370                            .concat_deferred_nodes(path_nodes, body_nodes);
9371                        let next_path = FastRepetitionPath {
9372                            index: body.index,
9373                            deferred_nodes,
9374                            diagnostics: self
9375                                .recognition_arena
9376                                .concat_diagnostics(path.diagnostics, body.diagnostics),
9377                            consumed_eof: path.consumed_eof || body.consumed_eof,
9378                        };
9379                        let symbol = self.token_type_at(next_path.index);
9380                        push_fast_repetition_work(
9381                            &mut work,
9382                            shape,
9383                            next_path,
9384                            lookahead.as_deref(),
9385                            symbol,
9386                        );
9387                    }
9388                }
9389                FastRepetitionWork::Exit(path) => {
9390                    if !coordinates.insert_exited(path) {
9391                        continue;
9392                    }
9393                    let path_nodes = if exit_alt_number == 0 {
9394                        path.deferred_nodes
9395                    } else {
9396                        let alternative =
9397                            self.recognition_arena.deferred_alternative(exit_alt_number);
9398                        self.recognition_arena
9399                            .concat_deferred_nodes(path.deferred_nodes, alternative)
9400                    };
9401                    let suffixes = self.recognize_state_fast(
9402                        atn,
9403                        FastRecognizeRequest {
9404                            state_number: shape.exit_target,
9405                            stop_state: request.stop_state,
9406                            index: path.index,
9407                            rule_start_index: request.rule_start_index,
9408                            decision_start_index: request.decision_start_index,
9409                            precedence: request.precedence,
9410                            depth: request.depth.saturating_add(1),
9411                            recovery_symbols: Rc::clone(&request.recovery_symbols),
9412                            recovery_state: request.recovery_state,
9413                        },
9414                        FastRecognizeScratch {
9415                            predicate_context,
9416                            visiting: &mut *visiting,
9417                            memo: &mut *memo,
9418                            expected: &mut *expected,
9419                            native_depth: native_depth + 1,
9420                        },
9421                    );
9422                    for mut outcome in suffixes {
9423                        outcome.deferred_nodes = self
9424                            .recognition_arena
9425                            .concat_deferred_nodes(path_nodes, outcome.deferred_nodes);
9426                        outcome.diagnostics = self
9427                            .recognition_arena
9428                            .concat_diagnostics(path.diagnostics, outcome.diagnostics);
9429                        outcome.consumed_eof |= path.consumed_eof;
9430                        outcomes.push(outcome);
9431                    }
9432                }
9433            }
9434        }
9435        dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
9436        outcomes
9437    }
9438
9439    /// Attempts to reach `stop_state` from `state_number` without committing
9440    /// token consumption to the parser's public stream position.
9441    fn recognize_state_fast(
9442        &mut self,
9443        atn: &Atn,
9444        request: FastRecognizeRequest,
9445        scratch: FastRecognizeScratch<'_, '_>,
9446    ) -> Vec<FastRecognizeOutcome> {
9447        if scratch.native_depth != 0 && scratch.native_depth < FAST_RECOGNIZE_STACK_CHECK_INTERVAL {
9448            return self.recognize_state_fast_inner(atn, request, scratch);
9449        }
9450        self.recognize_state_fast_checked(atn, request, scratch)
9451    }
9452
9453    #[inline(never)]
9454    fn recognize_state_fast_checked(
9455        &mut self,
9456        atn: &Atn,
9457        request: FastRecognizeRequest,
9458        mut scratch: FastRecognizeScratch<'_, '_>,
9459    ) -> Vec<FastRecognizeOutcome> {
9460        scratch.native_depth = 1;
9461        stacker::maybe_grow(FAST_RECOGNIZE_RED_ZONE, FAST_RECOGNIZE_STACK_SIZE, || {
9462            self.recognize_state_fast_inner(atn, request, scratch)
9463        })
9464    }
9465
9466    #[allow(clippy::too_many_lines)]
9467    fn recognize_state_fast_inner(
9468        &mut self,
9469        atn: &Atn,
9470        request: FastRecognizeRequest,
9471        scratch: FastRecognizeScratch<'_, '_>,
9472    ) -> Vec<FastRecognizeOutcome> {
9473        #[cfg(feature = "perf-counters")]
9474        perf_counters::inc(&perf_counters::RFS_CALLS, 1);
9475        let FastRecognizeScratch {
9476            predicate_context,
9477            visiting,
9478            memo,
9479            expected,
9480            native_depth,
9481        } = scratch;
9482        let FastRecognizeRequest {
9483            mut state_number,
9484            stop_state,
9485            mut index,
9486            rule_start_index,
9487            decision_start_index,
9488            precedence,
9489            mut depth,
9490            recovery_symbols,
9491            recovery_state,
9492        } = request;
9493        let max_token_type = atn.max_token_type();
9494        // Walk straight-line epsilon chains in a loop instead of recursing
9495        // into `recognize_state_fast` for each intermediate state. ATN
9496        // serialization places long sequences of `BasicBlock` epsilon
9497        // transitions between decisions: turning that chain into a loop
9498        // collapses many recursive calls (and their memo lookups, vec
9499        // allocations, and visit-set churn) into a single function frame.
9500        // The loop exits as soon as we hit the original state's logic
9501        // (multi-alt, decision, rule call, unmatched atom/range/set, gated
9502        // precedence) so existing fanout, recovery, and memoization still
9503        // apply unchanged.
9504        //
9505        // The inline case also handles single-atom-match states on the
9506        // happy-pass path: when the lone consuming transition matches the
9507        // current lookahead, advance the index and continue without paying
9508        // for a full `recognize_state_fast` recursion. We track tokens we
9509        // consumed inline in `inline_consumed_tokens` so they can be
9510        // prepended onto the eventual outcome list once we hit a state
9511        // whose handling falls outside this fast loop.
9512        let mut inline_consumed_tokens: Vec<usize> = Vec::new();
9513        let mut inline_consumed_eof = false;
9514        loop {
9515            if depth > RECOGNITION_DEPTH_LIMIT {
9516                return Vec::new();
9517            }
9518            if state_number == stop_state {
9519                let mut nodes = NodeSeqId::EMPTY;
9520                if self.fast_token_nodes_enabled {
9521                    for token_index in inline_consumed_tokens.iter().rev() {
9522                        let token = self.arena_token_node(*token_index, false);
9523                        self.arena_prepend(&mut nodes, token);
9524                    }
9525                }
9526                return vec![FastRecognizeOutcome {
9527                    index,
9528                    consumed_eof: inline_consumed_eof,
9529                    diagnostics: DiagnosticSeqId::EMPTY,
9530                    deferred_nodes: FastDeferredNodeId::EMPTY,
9531                    nodes,
9532                }];
9533            }
9534            let Some(state) = atn.state(state_number) else {
9535                return Vec::new();
9536            };
9537            let transitions = state.transitions();
9538            if transitions.len() == 1 && !state.precedence_rule_decision() {
9539                let transition = transitions
9540                    .first()
9541                    .expect("single transition checked above");
9542                let transition_kind = transition.kind();
9543                let target = transition.target();
9544                match transition_kind {
9545                    ParserTransitionKind::Epsilon | ParserTransitionKind::Action
9546                        if left_recursive_boundary(atn, state, target).is_none() =>
9547                    {
9548                        #[cfg(feature = "perf-counters")]
9549                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9550                        state_number = target;
9551                        depth += 1;
9552                        continue;
9553                    }
9554                    ParserTransitionKind::Predicate
9555                        if left_recursive_boundary(atn, state, target).is_none() =>
9556                    {
9557                        #[cfg(feature = "perf-counters")]
9558                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9559                        if !self.fast_parser_predicate_matches(predicate_context, transition, index)
9560                        {
9561                            record_predicate_no_viable(expected, decision_start_index, index);
9562                            return Vec::new();
9563                        }
9564                        state_number = target;
9565                        depth += 1;
9566                        continue;
9567                    }
9568                    ParserTransitionKind::Precedence
9569                        if packed_i32(transition.arg0()) >= precedence
9570                            && left_recursive_boundary(atn, state, target).is_none() =>
9571                    {
9572                        #[cfg(feature = "perf-counters")]
9573                        perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9574                        state_number = target;
9575                        depth += 1;
9576                        continue;
9577                    }
9578                    // Single-atom / range / set / wildcard / not-set states
9579                    // are common (~17K of ~125K calls on C#) and almost
9580                    // always succeed in pass 1: no fanout, no recovery, no
9581                    // diagnostics. Inline the token match and continue
9582                    // walking instead of recursing — the recursive path
9583                    // would just allocate a Vec, build one outcome, prepend
9584                    // a Token node, and return. Skip pass 2 (recovery
9585                    // enabled): there the failure branch matters and the
9586                    // existing recursive code records expected symbols.
9587                    ParserTransitionKind::Atom
9588                    | ParserTransitionKind::Range
9589                    | ParserTransitionKind::Set
9590                    | ParserTransitionKind::NotSet
9591                    | ParserTransitionKind::Wildcard
9592                        if !self.fast_recovery_enabled =>
9593                    {
9594                        let symbol = self.token_type_at(index);
9595                        if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
9596                            #[cfg(feature = "perf-counters")]
9597                            perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
9598                            if self.fast_token_nodes_enabled {
9599                                inline_consumed_tokens.push(index);
9600                            }
9601                            inline_consumed_eof |= symbol == TOKEN_EOF;
9602                            index = self.consume_index(index, symbol);
9603                            state_number = target;
9604                            depth += 1;
9605                            continue;
9606                        }
9607                        // Fall through to break and let the regular
9608                        // body handle the no-match case (returns empty).
9609                    }
9610                    _ => {}
9611                }
9612            }
9613            break;
9614        }
9615        // If we collected token nodes inline but bail to the recursive
9616        // body (decision state, rule call, etc.), the outcomes returned
9617        // below will need those token nodes prepended.
9618        let inline_pending = !inline_consumed_tokens.is_empty() || inline_consumed_eof;
9619        let Some(state) = atn.state(state_number) else {
9620            return Vec::new();
9621        };
9622        let transitions = state.transitions();
9623        let transition_count = transitions.len();
9624        if !self.fast_recovery_enabled
9625            && let Some(shape) = fast_repetition_shape(atn, state)
9626        {
9627            let mut outcomes = self.recognize_repetition_fast(
9628                atn,
9629                &FastRecognizeRequest {
9630                    state_number,
9631                    stop_state,
9632                    index,
9633                    rule_start_index,
9634                    decision_start_index,
9635                    precedence,
9636                    depth,
9637                    recovery_symbols: Rc::clone(&recovery_symbols),
9638                    recovery_state,
9639                },
9640                shape,
9641                FastRecognizeScratch {
9642                    predicate_context,
9643                    visiting: &mut *visiting,
9644                    memo: &mut *memo,
9645                    expected: &mut *expected,
9646                    native_depth: native_depth + 1,
9647                },
9648            );
9649            if inline_pending {
9650                for outcome in &mut outcomes {
9651                    outcome.consumed_eof |= inline_consumed_eof;
9652                    if self.fast_token_nodes_enabled {
9653                        for token_index in inline_consumed_tokens.iter().rev() {
9654                            let token = self.arena_token_node(*token_index, false);
9655                            self.defer_fast_outcome_node(outcome, token);
9656                        }
9657                    }
9658                }
9659            }
9660            return outcomes;
9661        }
9662        // In pass 1 (`fast_recovery_enabled == false`) the recovery-related
9663        // fields and the rule/decision boundary indices are pure plumbing —
9664        // they only affect the recovery branch and the no-viable diagnostic
9665        // recording, neither of which fires when recovery is off. Zeroing
9666        // them in the memo key collapses calls that visit the same
9667        // `(state, index)` from different rule-call sites onto one cache
9668        // entry, which is the dominant cost on large grammars (e.g. C#) where
9669        // many rules eventually delegate into the same `expression` /
9670        // `primary_expression` / `type` branches.
9671        let key = if self.fast_recovery_enabled {
9672            FastRecognizeKey {
9673                state_number,
9674                stop_state,
9675                index,
9676                rule_start_index,
9677                decision_start_index,
9678                precedence,
9679                recovery_symbols_id: Rc::as_ptr(&recovery_symbols) as usize,
9680                recovery_state,
9681            }
9682        } else {
9683            FastRecognizeKey {
9684                state_number,
9685                stop_state,
9686                index,
9687                rule_start_index: 0,
9688                decision_start_index: None,
9689                precedence,
9690                recovery_symbols_id: 0,
9691                recovery_state: None,
9692            }
9693        };
9694        // Once the clean-pass probe has established that coordinates do not
9695        // repeat, stop paying for the full memo table. Recovery always keeps
9696        // memoization because cached failures carry diagnostics, while
9697        // repeat-heavy clean parses promote before reaching sparse mode.
9698        let memo_lookup_enabled = self.fast_recovery_enabled
9699            || (transition_count > 1 && self.clean_memo_enabled_for_key(&key));
9700        if memo_lookup_enabled {
9701            if let Some(outcomes) = memo.get(&key) {
9702                #[cfg(feature = "perf-counters")]
9703                {
9704                    perf_counters::inc(&perf_counters::RFS_MEMO_HITS, 1);
9705                    perf_counters::inc(&perf_counters::OUTCOMES_CLONED, outcomes.len() as u64);
9706                }
9707                // Materialize a fresh `Vec` from the cached slice; the caller
9708                // mutates per-outcome state (eof flags, prepended nodes) so we
9709                // can't hand them the shared backing.
9710                if !inline_consumed_tokens.is_empty() || inline_consumed_eof {
9711                    let inline_eof = inline_consumed_eof;
9712                    let inline_tokens = &inline_consumed_tokens;
9713                    return outcomes
9714                        .iter()
9715                        .copied()
9716                        .map(|mut outcome| {
9717                            if inline_eof {
9718                                outcome.consumed_eof = true;
9719                            }
9720                            if self.fast_token_nodes_enabled {
9721                                for token_index in inline_tokens.iter().rev() {
9722                                    let token = self.arena_token_node(*token_index, false);
9723                                    self.defer_fast_outcome_node(&mut outcome, token);
9724                                }
9725                            }
9726                            outcome
9727                        })
9728                        .collect();
9729                }
9730                return outcomes.to_vec();
9731            }
9732            #[cfg(feature = "perf-counters")]
9733            perf_counters::inc(&perf_counters::RFS_MEMO_MISSES, 1);
9734        }
9735
9736        // Cycle detection: clean recognition keeps the narrow static cycle
9737        // guard used on hot paths. Recovery needs the broader epsilon-state
9738        // guard because an otherwise non-nullable loop body can recover as an
9739        // empty child at EOF and re-enter the loop at the same token.
9740        let needs_cycle_guard = if self.fast_recovery_enabled {
9741            transitions.iter().any(ParserTransition::is_epsilon)
9742        } else {
9743            transition_count > 1 && self.state_can_reenter_without_consuming(atn, state_number)
9744        };
9745        #[cfg(feature = "perf-counters")]
9746        if needs_cycle_guard {
9747            perf_counters::inc(&perf_counters::MULTI_TRANS_BODY, 1);
9748        } else {
9749            perf_counters::inc(&perf_counters::SINGLE_TRANS_BODY, 1);
9750            match state
9751                .transitions()
9752                .first()
9753                .expect("single-transition path requires one transition")
9754                .data()
9755            {
9756                Transition::Rule { .. } => {
9757                    perf_counters::inc(&perf_counters::SINGLE_TRANS_RULE, 1);
9758                }
9759                Transition::Atom { .. }
9760                | Transition::Range { .. }
9761                | Transition::Set { .. }
9762                | Transition::NotSet { .. }
9763                | Transition::Wildcard { .. } => {
9764                    perf_counters::inc(&perf_counters::SINGLE_TRANS_ATOM, 1);
9765                }
9766                _ => {
9767                    perf_counters::inc(&perf_counters::SINGLE_TRANS_OTHER, 1);
9768                }
9769            }
9770        }
9771        let has_inserted_cycle_guard = if needs_cycle_guard {
9772            if !visiting.insert(key.clone()) {
9773                #[cfg(feature = "perf-counters")]
9774                perf_counters::inc(&perf_counters::RFS_VISITING_CYCLE, 1);
9775                return Vec::new();
9776            }
9777            true
9778        } else {
9779            false
9780        };
9781        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
9782            Some(index)
9783        } else {
9784            decision_start_index
9785        };
9786        let (epsilon_recovery_symbols, epsilon_recovery_state) = if self.fast_recovery_enabled {
9787            fast_next_recovery_context(self, atn, state, &recovery_symbols, recovery_state)
9788        } else {
9789            (Rc::clone(&recovery_symbols), recovery_state)
9790        };
9791
9792        // Lookahead-based pruning. At a multi-alternative state we cache the
9793        // look-1 set of every outgoing transition; on visit we keep only the
9794        // transitions whose look-1 can accept the current lookahead (or that
9795        // can be reached without consuming and so could legitimately match a
9796        // shorter input). This is the main speedup vs. blind speculative
9797        // recursion: it lets each visit fan out only to the alternatives that
9798        // could possibly contribute a clean parse, mirroring the SLL phase of
9799        // ANTLR's adaptive prediction.
9800        //
9801        // Pruning is skipped at:
9802        //   * rule-start states (a child rule call may need every internal
9803        //     transition to surface single-token recovery diagnostics that
9804        //     ANTLR's reference parser emits at the rule's first consuming
9805        //     transition; the FIRST-set retry path turns the prefilter off
9806        //     entirely so let's keep this lightweight too),
9807        //   * left-recursive precedence loops (the precedence transition's
9808        //     gating is dynamic),
9809        //   * states with too few alternatives to benefit.
9810        let lookahead_filter = if transition_count > 1
9811            && self.fast_first_set_prefilter
9812            && !state.precedence_rule_decision()
9813            && (!self.fast_recovery_enabled || state.kind() != AtnStateKind::RuleStart)
9814        {
9815            state
9816                .rule_index()
9817                .and_then(|rule_index| atn.rule_to_stop_state().get(rule_index))
9818                .map(|rule_stop| {
9819                    let symbol = self.token_type_at(index);
9820                    let entry = self.cached_decision_lookahead(atn, state, rule_stop);
9821                    (symbol, entry)
9822                })
9823        } else {
9824            None
9825        };
9826        // LL(1) fast path: when the FIRST sets for the decision are disjoint
9827        // and none is nullable, the lookahead deterministically selects one
9828        // alternative. The recursive recognizer can then commit to that single
9829        // alt without iterating every transition through `should_skip_via_lookahead`
9830        // — saving (transition_count - 1) filter probes per visit.
9831        //
9832        // Result is cached per `(state, lookahead_token)` on the parser
9833        // instance, so subsequent visits skip the FIRST-set scan entirely.
9834        let ll1_only_alt: Option<usize> = if transition_count > 1
9835            && let Some((symbol, entry)) = lookahead_filter.as_ref()
9836        {
9837            let key = (state.state_number(), *symbol);
9838            if let Some(&cached) = self.ll1_decision_cache.get(&key) {
9839                cached
9840            } else {
9841                let result = ll1_unique_alt(entry, *symbol);
9842                self.ll1_decision_cache.insert(key, result);
9843                result
9844            }
9845        } else {
9846            None
9847        };
9848        let lookahead_filter = lookahead_filter.as_ref();
9849        // Pre-size only when we expect at least one outcome to land — most
9850        // single-transition fall-throughs (the loop above didn't catch
9851        // because they're atom/rule/predicate) push at most one entry, so
9852        // reserving one slot avoids a reallocation while keeping the
9853        // unused-slot waste at one element.
9854        let mut outcomes: Vec<FastRecognizeOutcome> = Vec::with_capacity(transition_count.min(2));
9855        for (transition_index, transition) in transitions.iter().enumerate() {
9856            if let Some(alt) = ll1_only_alt {
9857                // LL(1) determinism: skip every alt except the chosen one.
9858                if alt != transition_index {
9859                    continue;
9860                }
9861            }
9862            let transition_kind = transition.kind();
9863            if ll1_only_alt.is_none()
9864                && should_skip_via_lookahead(
9865                    transition_kind,
9866                    transition_index,
9867                    lookahead_filter,
9868                    index,
9869                    self.fast_recovery_enabled,
9870                    expected,
9871                )
9872            {
9873                continue;
9874            }
9875            let target = transition.target();
9876            let outcomes_before_transition = outcomes.len();
9877            let left_recursive_boundary = match transition_kind {
9878                ParserTransitionKind::Epsilon
9879                | ParserTransitionKind::Action
9880                | ParserTransitionKind::Predicate
9881                | ParserTransitionKind::Precedence => left_recursive_boundary(atn, state, target),
9882                ParserTransitionKind::Atom
9883                | ParserTransitionKind::Range
9884                | ParserTransitionKind::Set
9885                | ParserTransitionKind::NotSet
9886                | ParserTransitionKind::Wildcard
9887                | ParserTransitionKind::Rule => None,
9888            };
9889            match transition_kind {
9890                ParserTransitionKind::Epsilon | ParserTransitionKind::Action => {
9891                    #[cfg(feature = "perf-counters")]
9892                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9893                    outcomes.extend(self.recognize_state_fast(
9894                        atn,
9895                        FastRecognizeRequest {
9896                            state_number: target,
9897                            stop_state,
9898                            index,
9899                            rule_start_index,
9900                            decision_start_index: next_decision_start_index,
9901                            precedence,
9902                            depth: depth + 1,
9903                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9904                            recovery_state: epsilon_recovery_state,
9905                        },
9906                        FastRecognizeScratch {
9907                            predicate_context,
9908                            visiting,
9909                            memo,
9910                            expected,
9911                            native_depth: native_depth + 1,
9912                        },
9913                    ));
9914                }
9915                ParserTransitionKind::Predicate => {
9916                    #[cfg(feature = "perf-counters")]
9917                    perf_counters::inc(&perf_counters::EPSILON_TRANSITIONS, 1);
9918                    if self.fast_parser_predicate_matches(predicate_context, transition, index) {
9919                        outcomes.extend(self.recognize_state_fast(
9920                            atn,
9921                            FastRecognizeRequest {
9922                                state_number: target,
9923                                stop_state,
9924                                index,
9925                                rule_start_index,
9926                                decision_start_index: next_decision_start_index,
9927                                precedence,
9928                                depth: depth + 1,
9929                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9930                                recovery_state: epsilon_recovery_state,
9931                            },
9932                            FastRecognizeScratch {
9933                                predicate_context,
9934                                visiting,
9935                                memo,
9936                                expected,
9937                                native_depth: native_depth + 1,
9938                            },
9939                        ));
9940                    } else {
9941                        record_predicate_no_viable(expected, next_decision_start_index, index);
9942                    }
9943                }
9944                ParserTransitionKind::Precedence => {
9945                    let transition_precedence = packed_i32(transition.arg0());
9946                    if transition_precedence >= precedence {
9947                        outcomes.extend(self.recognize_state_fast(
9948                            atn,
9949                            FastRecognizeRequest {
9950                                state_number: target,
9951                                stop_state,
9952                                index,
9953                                rule_start_index,
9954                                decision_start_index: next_decision_start_index,
9955                                precedence,
9956                                depth: depth + 1,
9957                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
9958                                recovery_state: epsilon_recovery_state,
9959                            },
9960                            FastRecognizeScratch {
9961                                predicate_context,
9962                                visiting,
9963                                memo,
9964                                expected,
9965                                native_depth: native_depth + 1,
9966                            },
9967                        ));
9968                    }
9969                }
9970                ParserTransitionKind::Rule => {
9971                    let rule_index = transition.arg0() as usize;
9972                    let follow_state = transition.arg1() as usize;
9973                    let rule_precedence = packed_i32(transition.arg2());
9974                    #[cfg(feature = "perf-counters")]
9975                    perf_counters::inc(&perf_counters::RULE_TRANSITIONS, 1);
9976                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
9977                        continue;
9978                    };
9979                    // Lookahead-based pruning. The recognizer would otherwise
9980                    // explore every speculative rule call, producing exponential
9981                    // work on grammars with many epsilon-reachable rules. When
9982                    // the rule is non-nullable and its FIRST set excludes the
9983                    // current lookahead, recursion can't find a clean path
9984                    // *through this rule*. Skipping is only safe if some sibling
9985                    // transition can still consume the lookahead — otherwise the
9986                    // rule call is the sole continuation and must run so the
9987                    // single-token insertion / deletion recovery inside the
9988                    // called rule can fire (mirroring ANTLR's reference behavior
9989                    // of conjuring a missing token at child-rule entry).
9990                    let symbol = self.token_type_at(index);
9991                    if self.fast_first_set_prefilter {
9992                        // Probe the shared cross-parse cache first; build
9993                        // the entry on miss and intern it there. The
9994                        // computation is purely a function of the ATN, so
9995                        // the cached entry is reused across parses (and
9996                        // freshly-instantiated parser values that share
9997                        // the same `&'static Atn`).
9998                        //
9999                        // `rule_first_set` returns the computed entry
10000                        // directly — it intentionally skips inserting into
10001                        // the cache when the FIRST-set walk hit a cycle, so
10002                        // we cannot assume the entry is in the cache after
10003                        // computing it.
10004                        let first = self.cached_rule_first_set(atn, target, child_stop);
10005                        if should_skip_rule_via_first_set(
10006                            &first,
10007                            symbol,
10008                            self.fast_recovery_enabled,
10009                            index,
10010                            expected,
10011                        ) {
10012                            continue;
10013                        }
10014                    }
10015                    let expected_before_child =
10016                        self.fast_recovery_enabled.then(|| expected.clone());
10017                    let mut children = self.recognize_state_fast(
10018                        atn,
10019                        FastRecognizeRequest {
10020                            state_number: target,
10021                            stop_state: child_stop,
10022                            index,
10023                            rule_start_index: index,
10024                            decision_start_index: None,
10025                            precedence: rule_precedence,
10026                            depth: depth + 1,
10027                            recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
10028                            recovery_state: epsilon_recovery_state,
10029                        },
10030                        FastRecognizeScratch {
10031                            predicate_context,
10032                            visiting,
10033                            memo,
10034                            expected,
10035                            native_depth: native_depth + 1,
10036                        },
10037                    );
10038                    if children.is_empty() && self.fast_recovery_enabled {
10039                        children = self.fast_child_rule_failure_recovery_outcomes(
10040                            FastChildRuleFailureRecoveryRequest {
10041                                atn,
10042                                rule_index,
10043                                start_index: index,
10044                                follow_state,
10045                                stop_state,
10046                                expected,
10047                            },
10048                        );
10049                    }
10050                    if let Some(expected_before_child) = expected_before_child {
10051                        if children
10052                            .iter()
10053                            .any(|child| child.diagnostics.is_empty() && child.index > index)
10054                        {
10055                            *expected = expected_before_child;
10056                        }
10057                    }
10058                    for child in children {
10059                        let child_index = child.index;
10060                        let child_consumed_eof = child.consumed_eof;
10061                        let child_diagnostics = child.diagnostics;
10062                        let empty_recovery = self.empty_recovery_symbols();
10063                        let follow_outcomes = self.recognize_state_fast(
10064                            atn,
10065                            FastRecognizeRequest {
10066                                state_number: follow_state,
10067                                stop_state,
10068                                index: child_index,
10069                                rule_start_index,
10070                                decision_start_index: next_decision_start_index,
10071                                precedence,
10072                                depth: depth + 1,
10073                                recovery_symbols: empty_recovery,
10074                                recovery_state: None,
10075                            },
10076                            FastRecognizeScratch {
10077                                predicate_context,
10078                                visiting,
10079                                memo,
10080                                expected,
10081                                native_depth: native_depth + 1,
10082                            },
10083                        );
10084                        if follow_outcomes.is_empty() {
10085                            continue;
10086                        }
10087                        let child_stop_index =
10088                            self.rule_stop_token_index(child_index, child_consumed_eof);
10089                        let child_node = self.build_parse_trees.then(|| {
10090                            self.recognition_arena.deferred_rule_node(FastDeferredRule {
10091                                rule_index: u32::try_from(rule_index)
10092                                    .expect("rule index fits in u32"),
10093                                invoking_state: i32::try_from(invoking_state_number(state_number))
10094                                    .expect("invoking state fits in i32"),
10095                                start_index: u32::try_from(index)
10096                                    .expect("rule start index fits in u32"),
10097                                stop_index: child_stop_index.map(|stop_index| {
10098                                    u32::try_from(stop_index).expect("rule stop index fits in u32")
10099                                }),
10100                                deferred_children: child.deferred_nodes,
10101                                children: child.nodes,
10102                            })
10103                        });
10104                        let child_diags_empty = child_diagnostics.is_empty();
10105                        outcomes.extend(follow_outcomes.into_iter().map(|mut outcome| {
10106                            outcome.consumed_eof |= child_consumed_eof;
10107                            // Skip the prepend dance when there's nothing to
10108                            // merge from the child — common case in pass 1.
10109                            if !child_diags_empty {
10110                                outcome.diagnostics = self
10111                                    .recognition_arena
10112                                    .concat_diagnostics(child_diagnostics, outcome.diagnostics);
10113                            }
10114                            if let Some(child_node) = child_node {
10115                                outcome.deferred_nodes = self
10116                                    .recognition_arena
10117                                    .concat_deferred_nodes(child_node, outcome.deferred_nodes);
10118                            }
10119                            outcome
10120                        }));
10121                    }
10122                }
10123                ParserTransitionKind::Atom
10124                | ParserTransitionKind::Range
10125                | ParserTransitionKind::Set
10126                | ParserTransitionKind::NotSet
10127                | ParserTransitionKind::Wildcard => {
10128                    #[cfg(feature = "perf-counters")]
10129                    perf_counters::inc(&perf_counters::ATOM_RANGE_TRANSITIONS, 1);
10130                    let symbol = self.token_type_at(index);
10131                    if transition.matches_kind(transition_kind, symbol, 1, max_token_type) {
10132                        let next_index = self.consume_index(index, symbol);
10133                        let empty_recovery = self.empty_recovery_symbols();
10134                        outcomes.extend(
10135                            self.recognize_state_fast(
10136                                atn,
10137                                FastRecognizeRequest {
10138                                    state_number: target,
10139                                    stop_state,
10140                                    index: next_index,
10141                                    rule_start_index,
10142                                    decision_start_index: next_decision_start_index,
10143                                    precedence,
10144                                    depth: depth + 1,
10145                                    recovery_symbols: empty_recovery,
10146                                    recovery_state: None,
10147                                },
10148                                FastRecognizeScratch {
10149                                    predicate_context,
10150                                    visiting,
10151                                    memo,
10152                                    expected,
10153                                    native_depth: native_depth + 1,
10154                                },
10155                            )
10156                            .into_iter()
10157                            .map(|mut outcome| {
10158                                outcome.consumed_eof |= symbol == TOKEN_EOF;
10159                                if self.fast_token_nodes_enabled {
10160                                    let token = self.arena_token_node(index, false);
10161                                    self.defer_fast_outcome_node(&mut outcome, token);
10162                                }
10163                                outcome
10164                            }),
10165                        );
10166                    } else {
10167                        if !self.fast_recovery_enabled {
10168                            // In pass 1 there is no recovery to attempt; the
10169                            // recovery branch below would never run, and the
10170                            // `expected_symbols` computation is just there
10171                            // to gate that branch. Skipping it eliminates
10172                            // ~1× `state_expected_symbols` lookup per failed
10173                            // atom transition (≈82K on mono-statement.cs)
10174                            // for zero observable behavior change.
10175                            continue;
10176                        }
10177                        let expected_symbols = fast_recovery_expected_symbols(
10178                            self,
10179                            atn,
10180                            state.state_number(),
10181                            &recovery_symbols,
10182                        );
10183                        if expected_symbols.contains(&symbol) {
10184                            continue;
10185                        }
10186                        {
10187                            expected.record_transition(index, transition, max_token_type);
10188                            record_no_viable_if_ambiguous(
10189                                expected,
10190                                next_decision_start_index,
10191                                index,
10192                            );
10193                            outcomes.extend(self.fast_single_token_deletion_recovery(
10194                                FastRecoveryRequest {
10195                                    atn,
10196                                    transition,
10197                                    expected_symbols: Rc::clone(&expected_symbols),
10198                                    target,
10199                                    request: FastRecognizeRequest {
10200                                        state_number,
10201                                        stop_state,
10202                                        index,
10203                                        rule_start_index,
10204                                        decision_start_index,
10205                                        precedence,
10206                                        depth,
10207                                        recovery_symbols: Rc::clone(&recovery_symbols),
10208                                        recovery_state,
10209                                    },
10210                                    visiting,
10211                                    memo,
10212                                    expected,
10213                                },
10214                                predicate_context,
10215                            ));
10216                            if !state_is_left_recursive_rule(atn, state) {
10217                                outcomes.extend(self.fast_single_token_insertion_recovery(
10218                                    FastRecoveryRequest {
10219                                        atn,
10220                                        transition,
10221                                        expected_symbols: Rc::clone(&expected_symbols),
10222                                        target,
10223                                        request: FastRecognizeRequest {
10224                                            state_number,
10225                                            stop_state,
10226                                            index,
10227                                            rule_start_index,
10228                                            decision_start_index,
10229                                            precedence,
10230                                            depth,
10231                                            recovery_symbols: Rc::clone(&recovery_symbols),
10232                                            recovery_state,
10233                                        },
10234                                        visiting,
10235                                        memo,
10236                                        expected,
10237                                    },
10238                                    predicate_context,
10239                                ));
10240                            }
10241                            outcomes.extend(self.fast_current_token_deletion_recovery(
10242                                FastCurrentTokenDeletionRequest {
10243                                    atn,
10244                                    expected_symbols,
10245                                    request: FastRecognizeRequest {
10246                                        state_number,
10247                                        stop_state,
10248                                        index,
10249                                        rule_start_index,
10250                                        decision_start_index,
10251                                        precedence,
10252                                        depth,
10253                                        recovery_symbols: Rc::clone(&recovery_symbols),
10254                                        recovery_state,
10255                                    },
10256                                    visiting,
10257                                    memo,
10258                                    expected,
10259                                },
10260                                predicate_context,
10261                            ));
10262                        }
10263                    }
10264                }
10265            }
10266            let alt_number = next_alt_number(
10267                state,
10268                transition_count,
10269                transition_index,
10270                0,
10271                self.fast_track_alt_numbers,
10272            );
10273            if alt_number != 0 || left_recursive_boundary.is_some() {
10274                for outcome in &mut outcomes[outcomes_before_transition..] {
10275                    if alt_number != 0 {
10276                        self.defer_fast_outcome_alternative(outcome, alt_number);
10277                    }
10278                    if let Some(rule_index) = left_recursive_boundary {
10279                        self.defer_fast_outcome_boundary(outcome, rule_index);
10280                    }
10281                }
10282            }
10283        }
10284
10285        if has_inserted_cycle_guard {
10286            visiting.remove(&key);
10287        }
10288        if matches!(
10289            self.prediction_mode,
10290            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
10291        ) && self.fast_recovery_enabled
10292        {
10293            // Without recovery enabled every outcome already has empty
10294            // diagnostics, so the discard pass is a no-op — skipping it
10295            // saves an iter+retain on each of the ~1M visits.
10296            discard_recovered_fast_outcomes_if_clean_path_exists(&mut outcomes);
10297        }
10298        if self.fast_recovery_enabled {
10299            dedupe_fast_outcomes(&mut outcomes, &self.recognition_arena);
10300        } else {
10301            dedupe_clean_fast_outcomes(&mut outcomes, &mut self.fast_outcome_dedup);
10302        }
10303        // Skip memoization for single-transition states whose outcome is
10304        // unambiguous: they only get re-entered if the caller revisits the
10305        // exact same call site, which is rare since the loop above already
10306        // collapsed straight-line epsilon walks. Multi-alternative states
10307        // are where backtracking actually revisits the same coordinate, so
10308        // we still memoize there. With recovery on we keep the existing
10309        // memoization unconditionally because the recovery branch may
10310        // record diagnostics that the cache must surface to repeated
10311        // failed visits.
10312        let should_memoize = self.fast_recovery_enabled
10313            || (transition_count > 1 && self.clean_memo_mode != CleanMemoMode::Sparse);
10314        // Apply inline pending state to each outcome before returning.
10315        // Tokens consumed inline by the loop-collapse don't appear in the
10316        // recursive recognizer's output, so we need to prepend them here.
10317        let mut apply_inline_pending = |mut outcome: FastRecognizeOutcome| -> FastRecognizeOutcome {
10318            if inline_consumed_eof {
10319                outcome.consumed_eof = true;
10320            }
10321            if !inline_consumed_tokens.is_empty() {
10322                for token_index in inline_consumed_tokens.iter().rev() {
10323                    let token = self.arena_token_node(*token_index, false);
10324                    self.defer_fast_outcome_node(&mut outcome, token);
10325                }
10326            }
10327            outcome
10328        };
10329        if should_memoize {
10330            #[cfg(feature = "perf-counters")]
10331            {
10332                perf_counters::inc(&perf_counters::MEMO_INSERTED, 1);
10333                perf_counters::inc(&perf_counters::OUTCOMES_PUSHED, outcomes.len() as u64);
10334                match outcomes.len() {
10335                    0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10336                    1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10337                    _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10338                }
10339            }
10340            // The memo is keyed by the loop-exit `(state_number, index)` so
10341            // the inline-consumed tokens belong to *this* call's output, not
10342            // the cached result. Memoize the bare outcomes (without the
10343            // inline-pending data), then prepend the inline data on return.
10344            let stored: Rc<[FastRecognizeOutcome]> = Rc::from(outcomes);
10345            memo.insert(key, Rc::clone(&stored));
10346            if inline_pending {
10347                return stored
10348                    .iter()
10349                    .copied()
10350                    .map(&mut apply_inline_pending)
10351                    .collect();
10352            }
10353            return stored.to_vec();
10354        }
10355        #[cfg(feature = "perf-counters")]
10356        match outcomes.len() {
10357            0 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_0, 1),
10358            1 => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_1, 1),
10359            _ => perf_counters::inc(&perf_counters::OUTCOMES_RETURN_N, 1),
10360        }
10361        if inline_pending {
10362            return outcomes.into_iter().map(apply_inline_pending).collect();
10363        }
10364        outcomes
10365    }
10366
10367    /// Explores single-token deletion recovery while preserving the matched
10368    /// token and skipped error token in the selected parse tree path.
10369    fn single_token_deletion_recovery(
10370        &mut self,
10371        recovery: RecoveryRequest<'_, '_>,
10372    ) -> Vec<RecognizeOutcome> {
10373        let RecoveryRequest {
10374            atn,
10375            transition,
10376            expected_symbols,
10377            target,
10378            request,
10379            visiting,
10380            memo,
10381            expected,
10382        } = recovery;
10383        let RecognizeRequest {
10384            stop_state,
10385            index,
10386            rule_start_index,
10387            decision_start_index,
10388            init_action_rules,
10389            predicates,
10390            semantics,
10391            rule_args,
10392            member_actions,
10393            return_actions,
10394            local_int_arg,
10395            member_values,
10396            return_values,
10397            rule_alt_number,
10398            track_alt_numbers,
10399            consumed_eof,
10400            precedence,
10401            depth,
10402            ..
10403        } = request;
10404        let Some((diagnostic, next_index, next_symbol)) =
10405            self.single_token_deletion(transition, index, atn.max_token_type(), &expected_symbols)
10406        else {
10407            return Vec::new();
10408        };
10409        let after_next = self.consume_index(next_index, next_symbol);
10410        self.recognize_state(
10411            atn,
10412            RecognizeRequest {
10413                state_number: target,
10414                stop_state,
10415                index: after_next,
10416                rule_start_index,
10417                decision_start_index,
10418                init_action_rules,
10419                predicates,
10420                semantics,
10421                rule_args,
10422                member_actions,
10423                return_actions,
10424                local_int_arg,
10425                member_values,
10426                return_values,
10427                rule_alt_number,
10428                track_alt_numbers,
10429                consumed_eof: consumed_eof || next_symbol == TOKEN_EOF,
10430                committed_decision: false,
10431                precedence,
10432                depth: depth + 1,
10433                recovery_symbols: BTreeSet::new(),
10434                recovery_state: None,
10435            },
10436            visiting,
10437            memo,
10438            expected,
10439        )
10440        .into_iter()
10441        .map(|mut outcome| {
10442            outcome.consumed_eof |= next_symbol == TOKEN_EOF;
10443            outcome.diagnostics = self
10444                .recognition_arena
10445                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10446            let token = self.arena_token_node(next_index, false);
10447            self.arena_prepend(&mut outcome.nodes, token);
10448            let error = self.arena_token_node(index, true);
10449            self.arena_prepend(&mut outcome.nodes, error);
10450            outcome
10451        })
10452        .collect()
10453    }
10454
10455    /// Retries the current recognition state after deleting one unexpected
10456    /// token, preserving the deleted token as an error node in the parse tree.
10457    fn current_token_deletion_recovery(
10458        &mut self,
10459        recovery: CurrentTokenDeletionRequest<'_, '_>,
10460    ) -> Vec<RecognizeOutcome> {
10461        let CurrentTokenDeletionRequest {
10462            atn,
10463            expected_symbols,
10464            mut request,
10465            visiting,
10466            memo,
10467            expected,
10468        } = recovery;
10469        let error_index = request.index;
10470        if error_index == request.rule_start_index {
10471            return Vec::new();
10472        }
10473        let Some((diagnostic, next_index, skipped)) =
10474            self.current_token_deletion(error_index, &expected_symbols)
10475        else {
10476            return Vec::new();
10477        };
10478        request.state_number = request.recovery_state.unwrap_or(request.state_number);
10479        request.index = next_index;
10480        request.committed_decision = false;
10481        request.depth += 1;
10482        request.recovery_state = None;
10483        self.recognize_state(atn, request, visiting, memo, expected)
10484            .into_iter()
10485            .map(|mut outcome| {
10486                outcome.diagnostics = self
10487                    .recognition_arena
10488                    .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10489                for index in skipped.iter().rev() {
10490                    let error = self.arena_token_node(*index, true);
10491                    self.arena_prepend(&mut outcome.nodes, error);
10492                }
10493                outcome
10494            })
10495            .collect()
10496    }
10497
10498    /// Falls back after deletion/insertion repairs cannot continue from a
10499    /// failed consuming transition.
10500    fn consuming_failure_fallback(
10501        &mut self,
10502        fallback: ConsumingFailureFallback<'_>,
10503        visiting: &mut BTreeSet<RecognizeKey>,
10504        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10505        expected: &mut ExpectedTokens,
10506    ) -> Vec<RecognizeOutcome> {
10507        if fallback.expected_symbols.is_empty() {
10508            return Vec::new();
10509        }
10510        if fallback.symbol == TOKEN_EOF {
10511            return self.eof_consuming_failure_fallback(fallback, expected);
10512        }
10513        self.non_eof_consuming_failure_fallback(fallback, visiting, memo, expected)
10514    }
10515
10516    /// Keeps unexpected non-EOF input visible as an error node when no repair
10517    /// path can otherwise reach the transition target.
10518    fn non_eof_consuming_failure_fallback(
10519        &mut self,
10520        fallback: ConsumingFailureFallback<'_>,
10521        visiting: &mut BTreeSet<RecognizeKey>,
10522        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10523        expected: &mut ExpectedTokens,
10524    ) -> Vec<RecognizeOutcome> {
10525        let ConsumingFailureFallback {
10526            atn,
10527            target,
10528            request,
10529            symbol,
10530            expected_symbols,
10531            decision_start_index,
10532            decision,
10533        } = fallback;
10534        let error_index = request.index;
10535        let diagnostic =
10536            self.recovery_failure_diagnostic(error_index, decision_start_index, &expected_symbols);
10537        let next_index = self.consume_index(error_index, symbol);
10538        self.recognize_state(
10539            atn,
10540            RecognizeRequest {
10541                state_number: target,
10542                stop_state: request.stop_state,
10543                index: next_index,
10544                rule_start_index: request.rule_start_index,
10545                decision_start_index,
10546                init_action_rules: request.init_action_rules,
10547                predicates: request.predicates,
10548                semantics: request.semantics,
10549                rule_args: request.rule_args,
10550                member_actions: request.member_actions,
10551                return_actions: request.return_actions,
10552                local_int_arg: request.local_int_arg,
10553                member_values: request.member_values,
10554                return_values: request.return_values,
10555                rule_alt_number: request.rule_alt_number,
10556                track_alt_numbers: request.track_alt_numbers,
10557                consumed_eof: request.consumed_eof,
10558                committed_decision: false,
10559                precedence: request.precedence,
10560                depth: request.depth + 1,
10561                recovery_symbols: BTreeSet::new(),
10562                recovery_state: None,
10563            },
10564            visiting,
10565            memo,
10566            expected,
10567        )
10568        .into_iter()
10569        .map(|mut outcome| {
10570            prepend_decision(&mut outcome, decision);
10571            outcome.diagnostics = self
10572                .recognition_arena
10573                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10574            let error = self.arena_token_node(error_index, true);
10575            self.arena_prepend(&mut outcome.nodes, error);
10576            outcome
10577        })
10578        .collect()
10579    }
10580
10581    /// Stops the current rule at EOF after a nested failure, matching ANTLR's
10582    /// behavior of unwinding instead of inserting caller tokens at EOF.
10583    fn eof_consuming_failure_fallback(
10584        &mut self,
10585        fallback: ConsumingFailureFallback<'_>,
10586        expected: &ExpectedTokens,
10587    ) -> Vec<RecognizeOutcome> {
10588        let request = fallback.request;
10589        if request.index == request.rule_start_index {
10590            return Vec::new();
10591        }
10592        let diagnostic =
10593            self.eof_rule_recovery_diagnostic(request.index, &fallback.expected_symbols, expected);
10594        let diagnostics = self
10595            .recognition_arena
10596            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
10597        vec![RecognizeOutcome {
10598            index: request.index,
10599            consumed_eof: request.consumed_eof,
10600            alt_number: request.rule_alt_number,
10601            member_values: request.member_values,
10602            return_values: request.return_values,
10603            diagnostics,
10604            decisions: Vec::new(),
10605            actions: Vec::new(),
10606            nodes: NodeSeqId::EMPTY,
10607        }]
10608    }
10609
10610    /// Explores single-token insertion recovery while adding a conjured
10611    /// missing-token error node to the selected parse tree path.
10612    fn single_token_insertion_recovery(
10613        &mut self,
10614        recovery: RecoveryRequest<'_, '_>,
10615    ) -> Vec<RecognizeOutcome> {
10616        let RecoveryRequest {
10617            atn,
10618            transition,
10619            expected_symbols,
10620            target,
10621            request,
10622            visiting,
10623            memo,
10624            expected,
10625        } = recovery;
10626        let RecognizeRequest {
10627            stop_state,
10628            index,
10629            rule_start_index,
10630            decision_start_index,
10631            init_action_rules,
10632            predicates,
10633            semantics,
10634            rule_args,
10635            member_actions,
10636            return_actions,
10637            local_int_arg,
10638            member_values,
10639            return_values,
10640            rule_alt_number,
10641            track_alt_numbers,
10642            consumed_eof,
10643            precedence,
10644            depth,
10645            ..
10646        } = request;
10647        let follow_symbols = state_expected_symbols(atn, transition.target());
10648        let Some((diagnostic, token_type, text)) = self.single_token_insertion(
10649            transition,
10650            index,
10651            atn.max_token_type(),
10652            &expected_symbols,
10653            &follow_symbols,
10654        ) else {
10655            return Vec::new();
10656        };
10657        self.recognize_state(
10658            atn,
10659            RecognizeRequest {
10660                state_number: target,
10661                stop_state,
10662                index,
10663                rule_start_index,
10664                decision_start_index,
10665                init_action_rules,
10666                predicates,
10667                semantics,
10668                rule_args,
10669                member_actions,
10670                return_actions,
10671                local_int_arg,
10672                member_values,
10673                return_values,
10674                rule_alt_number,
10675                track_alt_numbers,
10676                consumed_eof,
10677                committed_decision: false,
10678                precedence,
10679                depth: depth + 1,
10680                recovery_symbols: BTreeSet::new(),
10681                recovery_state: None,
10682            },
10683            visiting,
10684            memo,
10685            expected,
10686        )
10687        .into_iter()
10688        .map(|mut outcome| {
10689            outcome.diagnostics = self
10690                .recognition_arena
10691                .prepend_diagnostic(outcome.diagnostics, diagnostic.clone());
10692            let missing = self.arena_missing_token_node(token_type, index, text.clone());
10693            self.arena_prepend(&mut outcome.nodes, missing);
10694            outcome
10695        })
10696        .collect()
10697    }
10698
10699    /// Attempts to reach `stop_state` and carries semantic actions for the
10700    /// selected parser path.
10701    #[allow(clippy::too_many_lines)]
10702    fn recognize_state(
10703        &mut self,
10704        atn: &Atn,
10705        request: RecognizeRequest<'_>,
10706        visiting: &mut BTreeSet<RecognizeKey>,
10707        memo: &mut BTreeMap<RecognizeKey, Vec<RecognizeOutcome>>,
10708        expected: &mut ExpectedTokens,
10709    ) -> Vec<RecognizeOutcome> {
10710        let request_template = request.clone();
10711        let RecognizeRequest {
10712            state_number,
10713            stop_state,
10714            index,
10715            rule_start_index,
10716            decision_start_index,
10717            init_action_rules,
10718            predicates,
10719            semantics,
10720            rule_args,
10721            member_actions,
10722            return_actions,
10723            local_int_arg,
10724            member_values,
10725            return_values,
10726            rule_alt_number,
10727            track_alt_numbers,
10728            consumed_eof,
10729            committed_decision,
10730            precedence,
10731            depth,
10732            recovery_symbols,
10733            recovery_state,
10734        } = request;
10735        if depth > RECOGNITION_DEPTH_LIMIT {
10736            return Vec::new();
10737        }
10738        if state_number == stop_state {
10739            return stop_outcome(
10740                index,
10741                consumed_eof,
10742                rule_alt_number,
10743                member_values,
10744                return_values,
10745            );
10746        }
10747        let key = RecognizeKey {
10748            state_number,
10749            stop_state,
10750            index,
10751            rule_start_index,
10752            decision_start_index,
10753            local_int_arg,
10754            member_values: member_values.clone(),
10755            return_values: return_values.clone(),
10756            rule_alt_number,
10757            track_alt_numbers,
10758            consumed_eof,
10759            committed_decision,
10760            precedence,
10761            recovery_symbols: recovery_symbols.clone(),
10762            recovery_state,
10763        };
10764        if let Some(outcomes) = memo.get(&key) {
10765            return outcomes.clone();
10766        }
10767
10768        let visit_key = key.clone();
10769        if !visiting.insert(visit_key.clone()) {
10770            return Vec::new();
10771        }
10772
10773        let Some(state) = atn.state(state_number) else {
10774            visiting.remove(&visit_key);
10775            return Vec::new();
10776        };
10777        let decision_override_generation = self.decision_override_generation;
10778        let transitions = state.transitions();
10779        let transition_count = transitions.len();
10780        let overridden_transition = if transition_count > 1
10781            && self.semantic_hooks.observes_parser_decisions()
10782        {
10783            atn.decision_to_state()
10784                .iter()
10785                .position(|candidate| candidate == state_number)
10786                .and_then(|decision| {
10787                    self.semantic_hooks
10788                        .parser_decision_override(decision, index, transition_count)
10789                })
10790                .and_then(|alternative| alternative.checked_sub(1))
10791                .filter(|alternative| *alternative < transition_count)
10792        } else {
10793            None
10794        };
10795        if overridden_transition.is_some() {
10796            self.decision_override_generation = self.decision_override_generation.wrapping_add(1);
10797        }
10798        let next_decision_start_index = if starts_prediction_decision(state, transition_count) {
10799            Some(index)
10800        } else {
10801            decision_start_index
10802        };
10803        let (epsilon_recovery_symbols, epsilon_recovery_state) =
10804            next_recovery_context(atn, state, &recovery_symbols, recovery_state);
10805        let mut outcomes = Vec::new();
10806        for (transition_index, transition) in transitions.iter().enumerate() {
10807            if overridden_transition.is_some_and(|forced| forced != transition_index) {
10808                continue;
10809            }
10810            let transition_committed =
10811                committed_decision || overridden_transition == Some(transition_index);
10812            let mut transition_request = request_template.clone();
10813            transition_request.committed_decision = transition_committed;
10814            let decision =
10815                transition_decision(atn, state, transition_count, transition_index, predicates);
10816            let next_alt_number = next_alt_number(
10817                state,
10818                transition_count,
10819                transition_index,
10820                rule_alt_number,
10821                track_alt_numbers,
10822            );
10823            let transition_data = transition.data();
10824            match &transition_data {
10825                Transition::Epsilon { target } | Transition::Action { target, .. } => {
10826                    let (action_rule_index, action_index) = match &transition_data {
10827                        Transition::Action {
10828                            rule_index,
10829                            action_index,
10830                            ..
10831                        } => (Some(*rule_index), *action_index),
10832                        _ => (None, None),
10833                    };
10834                    outcomes.extend(self.recognize_epsilon_or_action_step(
10835                        atn,
10836                        &transition_request,
10837                        EpsilonActionStep {
10838                            source_state: state_number,
10839                            target: *target,
10840                            action_rule_index,
10841                            action_index,
10842                            left_recursive_boundary: left_recursive_boundary(atn, state, *target),
10843                            decision,
10844                            decision_start_index: next_decision_start_index,
10845                            alt_number: next_alt_number,
10846                            recovery_symbols: epsilon_recovery_symbols.clone(),
10847                            recovery_state: epsilon_recovery_state,
10848                        },
10849                        RecognizeScratch {
10850                            visiting,
10851                            memo,
10852                            expected,
10853                        },
10854                    ));
10855                }
10856                Transition::Predicate {
10857                    target,
10858                    rule_index,
10859                    pred_index,
10860                    ..
10861                } => {
10862                    let predicate = PredicateEval {
10863                        index,
10864                        rule_index: *rule_index,
10865                        pred_index: *pred_index,
10866                        predicates,
10867                        semantics,
10868                        context: None,
10869                        local_int_arg,
10870                        member_values: &member_values,
10871                    };
10872                    if self.parser_predicate_matches(predicate) {
10873                        let left_recursive_boundary = left_recursive_boundary(atn, state, *target);
10874                        outcomes.extend(
10875                            self.recognize_state(
10876                                atn,
10877                                RecognizeRequest {
10878                                    state_number: *target,
10879                                    stop_state,
10880                                    index,
10881                                    rule_start_index,
10882                                    decision_start_index: next_decision_start_index,
10883                                    init_action_rules,
10884                                    predicates,
10885                                    semantics,
10886                                    rule_args,
10887                                    member_actions,
10888                                    return_actions,
10889                                    local_int_arg,
10890                                    member_values: member_values.clone(),
10891                                    return_values: return_values.clone(),
10892                                    rule_alt_number: next_alt_number,
10893                                    track_alt_numbers,
10894                                    consumed_eof,
10895                                    committed_decision: transition_committed,
10896                                    precedence,
10897                                    depth: depth + 1,
10898                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10899                                    recovery_state: epsilon_recovery_state,
10900                                },
10901                                visiting,
10902                                memo,
10903                                expected,
10904                            )
10905                            .into_iter()
10906                            .map(|mut outcome| {
10907                                prepend_decision(&mut outcome, decision);
10908                                if let Some(rule_index) = left_recursive_boundary {
10909                                    let boundary =
10910                                        self.arena_boundary_node(rule_index, next_alt_number);
10911                                    self.arena_prepend(&mut outcome.nodes, boundary);
10912                                }
10913                                outcome
10914                            }),
10915                        );
10916                    } else if let Some(message) = semantics
10917                        .and_then(|semantics| {
10918                            self.parser_semantic_ir_predicate_failure_message(
10919                                *rule_index,
10920                                *pred_index,
10921                                semantics,
10922                            )
10923                        })
10924                        .or_else(|| {
10925                            self.parser_predicate_failure_message(
10926                                *rule_index,
10927                                *pred_index,
10928                                predicates,
10929                            )
10930                        })
10931                    {
10932                        outcomes.push(self.predicate_failure_recovery(PredicateFailureRecovery {
10933                            rule_index: *rule_index,
10934                            index,
10935                            message,
10936                            member_values: member_values.clone(),
10937                            return_values: return_values.clone(),
10938                            rule_alt_number,
10939                        }));
10940                    } else {
10941                        record_predicate_no_viable(expected, next_decision_start_index, index);
10942                    }
10943                }
10944                Transition::Precedence {
10945                    target,
10946                    precedence: transition_precedence,
10947                } => {
10948                    if *transition_precedence >= precedence {
10949                        outcomes.extend(
10950                            self.recognize_state(
10951                                atn,
10952                                RecognizeRequest {
10953                                    state_number: *target,
10954                                    stop_state,
10955                                    index,
10956                                    rule_start_index,
10957                                    decision_start_index: next_decision_start_index,
10958                                    init_action_rules,
10959                                    predicates,
10960                                    semantics,
10961                                    rule_args,
10962                                    member_actions,
10963                                    return_actions,
10964                                    local_int_arg,
10965                                    member_values: member_values.clone(),
10966                                    return_values: return_values.clone(),
10967                                    rule_alt_number: next_alt_number,
10968                                    track_alt_numbers,
10969                                    consumed_eof,
10970                                    committed_decision: transition_committed,
10971                                    precedence,
10972                                    depth: depth + 1,
10973                                    recovery_symbols: epsilon_recovery_symbols.clone(),
10974                                    recovery_state: epsilon_recovery_state,
10975                                },
10976                                visiting,
10977                                memo,
10978                                expected,
10979                            )
10980                            .into_iter()
10981                            .map(|mut outcome| {
10982                                prepend_decision(&mut outcome, decision);
10983                                outcome
10984                            }),
10985                        );
10986                    }
10987                }
10988                Transition::Rule {
10989                    target,
10990                    rule_index,
10991                    follow_state,
10992                    precedence: rule_precedence,
10993                    ..
10994                } => {
10995                    let Some(child_stop) = atn.rule_to_stop_state().get(*rule_index) else {
10996                        continue;
10997                    };
10998                    let child_local_int_arg =
10999                        rule_local_int_arg(rule_args, state_number, *rule_index, local_int_arg);
11000                    let expected_before_child = expected.clone();
11001                    let children = self.recognize_state(
11002                        atn,
11003                        RecognizeRequest {
11004                            state_number: *target,
11005                            stop_state: child_stop,
11006                            index,
11007                            rule_start_index: index,
11008                            decision_start_index: None,
11009                            init_action_rules,
11010                            predicates,
11011                            semantics,
11012                            rule_args,
11013                            member_actions,
11014                            return_actions,
11015                            local_int_arg: child_local_int_arg,
11016                            member_values: member_values.clone(),
11017                            return_values: BTreeMap::new(),
11018                            rule_alt_number: 0,
11019                            track_alt_numbers,
11020                            consumed_eof: false,
11021                            committed_decision: transition_committed,
11022                            precedence: *rule_precedence,
11023                            depth: depth + 1,
11024                            recovery_symbols: epsilon_recovery_symbols.clone(),
11025                            recovery_state: epsilon_recovery_state,
11026                        },
11027                        visiting,
11028                        memo,
11029                        expected,
11030                    );
11031                    let children = if children.is_empty() {
11032                        self.child_rule_failure_recovery_outcomes(ChildRuleFailureRecovery {
11033                            atn,
11034                            rule_index: *rule_index,
11035                            start_index: index,
11036                            follow_state: *follow_state,
11037                            stop_state,
11038                            member_values: member_values.clone(),
11039                            expected,
11040                        })
11041                    } else {
11042                        children
11043                    };
11044                    let preserve_child_expected =
11045                        self.child_expected_reaches_clean_eof(&children, expected);
11046                    restore_expected(
11047                        &children,
11048                        index,
11049                        expected,
11050                        expected_before_child,
11051                        preserve_child_expected,
11052                    );
11053                    for child in children {
11054                        let child_stop_index =
11055                            self.rule_stop_token_index(child.index, child.consumed_eof);
11056                        let child_nodes = self
11057                            .recognition_arena
11058                            .fold_left_recursive_boundaries(child.nodes);
11059                        let child_node = self.arena_rule_node(ArenaRuleSpec {
11060                            rule_index: *rule_index,
11061                            invoking_state: invoking_state_number(state_number),
11062                            alt_number: child.alt_number,
11063                            start_index: index,
11064                            stop_index: child_stop_index,
11065                            return_values: child.return_values.clone(),
11066                            children: child_nodes,
11067                        });
11068                        outcomes.extend(
11069                            self.recognize_state(
11070                                atn,
11071                                RecognizeRequest {
11072                                    state_number: *follow_state,
11073                                    stop_state,
11074                                    index: child.index,
11075                                    rule_start_index,
11076                                    decision_start_index: next_decision_start_index,
11077                                    init_action_rules,
11078                                    predicates,
11079                                    semantics,
11080                                    rule_args,
11081                                    member_actions,
11082                                    return_actions,
11083                                    local_int_arg,
11084                                    member_values: child.member_values.clone(),
11085                                    return_values: return_values.clone(),
11086                                    rule_alt_number,
11087                                    track_alt_numbers,
11088                                    consumed_eof: consumed_eof || child.consumed_eof,
11089                                    committed_decision: transition_committed
11090                                        && child.index == index,
11091                                    precedence,
11092                                    depth: depth + 1,
11093                                    recovery_symbols: BTreeSet::new(),
11094                                    recovery_state: None,
11095                                },
11096                                visiting,
11097                                memo,
11098                                expected,
11099                            )
11100                            .into_iter()
11101                            .map(|mut outcome| {
11102                                outcome.consumed_eof |= child.consumed_eof;
11103                                outcome.diagnostics = self
11104                                    .recognition_arena
11105                                    .concat_diagnostics(child.diagnostics, outcome.diagnostics);
11106                                let mut decisions = child.decisions.clone();
11107                                decisions.append(&mut outcome.decisions);
11108                                outcome.decisions = decisions;
11109                                prepend_decision(&mut outcome, decision);
11110                                let mut actions = child.actions.clone();
11111                                if init_action_rules.contains(rule_index) {
11112                                    actions.insert(
11113                                        0,
11114                                        ParserAction::new_rule_init(
11115                                            *rule_index,
11116                                            index,
11117                                            Some(*follow_state),
11118                                        ),
11119                                    );
11120                                }
11121                                actions.append(&mut outcome.actions);
11122                                outcome.actions = actions;
11123                                self.arena_prepend(&mut outcome.nodes, child_node);
11124                                outcome
11125                            }),
11126                        );
11127                    }
11128                }
11129                Transition::Atom { target, .. }
11130                | Transition::Range { target, .. }
11131                | Transition::Set { target, .. }
11132                | Transition::NotSet { target, .. }
11133                | Transition::Wildcard { target, .. } => {
11134                    let symbol = self.token_type_at(index);
11135                    if transition_data.matches(symbol, 1, atn.max_token_type()) {
11136                        let next_index = self.consume_index(index, symbol);
11137                        outcomes.extend(
11138                            self.recognize_state(
11139                                atn,
11140                                RecognizeRequest {
11141                                    state_number: *target,
11142                                    stop_state,
11143                                    index: next_index,
11144                                    rule_start_index,
11145                                    decision_start_index: next_decision_start_index,
11146                                    init_action_rules,
11147                                    predicates,
11148                                    semantics,
11149                                    rule_args,
11150                                    member_actions,
11151                                    return_actions,
11152                                    local_int_arg,
11153                                    member_values: member_values.clone(),
11154                                    return_values: return_values.clone(),
11155                                    rule_alt_number: next_alt_number,
11156                                    track_alt_numbers,
11157                                    consumed_eof: consumed_eof || symbol == TOKEN_EOF,
11158                                    committed_decision: false,
11159                                    precedence,
11160                                    depth: depth + 1,
11161                                    recovery_symbols: BTreeSet::new(),
11162                                    recovery_state: None,
11163                                },
11164                                visiting,
11165                                memo,
11166                                expected,
11167                            )
11168                            .into_iter()
11169                            .map(|mut outcome| {
11170                                prepend_decision(&mut outcome, decision);
11171                                outcome.consumed_eof |= symbol == TOKEN_EOF;
11172                                let token = self.arena_token_node(index, false);
11173                                self.arena_prepend(&mut outcome.nodes, token);
11174                                outcome
11175                            }),
11176                        );
11177                    } else {
11178                        let expected_symbols =
11179                            recovery_expected_symbols(atn, state.state_number(), &recovery_symbols);
11180                        if expected_symbols.contains(&symbol) && !transition_committed {
11181                            continue;
11182                        }
11183                        expected.record_transition(index, transition, atn.max_token_type());
11184                        record_no_viable_if_ambiguous(expected, next_decision_start_index, index);
11185                        let before_recovery = outcomes.len();
11186                        let recovery_request = transition_request.clone();
11187                        if transition_committed {
11188                            outcomes.extend(self.consuming_failure_fallback(
11189                                ConsumingFailureFallback {
11190                                    atn,
11191                                    target: *target,
11192                                    request: recovery_request,
11193                                    symbol,
11194                                    expected_symbols,
11195                                    decision_start_index: next_decision_start_index,
11196                                    decision,
11197                                },
11198                                visiting,
11199                                memo,
11200                                expected,
11201                            ));
11202                            break;
11203                        }
11204                        outcomes.extend(
11205                            self.single_token_deletion_recovery(RecoveryRequest {
11206                                atn,
11207                                transition,
11208                                expected_symbols: expected_symbols.clone(),
11209                                target: *target,
11210                                request: recovery_request.clone(),
11211                                visiting,
11212                                memo,
11213                                expected,
11214                            })
11215                            .into_iter()
11216                            .map(|mut outcome| {
11217                                prepend_decision(&mut outcome, decision);
11218                                outcome
11219                            }),
11220                        );
11221                        if !state_is_left_recursive_rule(atn, state) {
11222                            outcomes.extend(
11223                                self.single_token_insertion_recovery(RecoveryRequest {
11224                                    atn,
11225                                    transition,
11226                                    expected_symbols: expected_symbols.clone(),
11227                                    target: *target,
11228                                    request: recovery_request.clone(),
11229                                    visiting,
11230                                    memo,
11231                                    expected,
11232                                })
11233                                .into_iter()
11234                                .map(|mut outcome| {
11235                                    prepend_decision(&mut outcome, decision);
11236                                    outcome
11237                                }),
11238                            );
11239                        }
11240                        outcomes.extend(self.current_token_deletion_recovery(
11241                            CurrentTokenDeletionRequest {
11242                                atn,
11243                                expected_symbols: expected_symbols.clone(),
11244                                request: recovery_request.clone(),
11245                                visiting,
11246                                memo,
11247                                expected,
11248                            },
11249                        ));
11250                        if outcomes.len() == before_recovery {
11251                            outcomes.extend(self.consuming_failure_fallback(
11252                                ConsumingFailureFallback {
11253                                    atn,
11254                                    target: *target,
11255                                    request: recovery_request,
11256                                    symbol,
11257                                    expected_symbols,
11258                                    decision_start_index: next_decision_start_index,
11259                                    decision,
11260                                },
11261                                visiting,
11262                                memo,
11263                                expected,
11264                            ));
11265                        }
11266                    }
11267                }
11268            }
11269            if self.decision_override_generation != decision_override_generation {
11270                break;
11271            }
11272        }
11273
11274        visiting.remove(&visit_key);
11275        self.record_prediction_diagnostics(atn, state, index, &outcomes);
11276        if matches!(
11277            self.prediction_mode,
11278            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
11279        ) {
11280            discard_recovered_outcomes_if_clean_path_exists(&mut outcomes, &self.recognition_arena);
11281        }
11282        dedupe_outcomes(&mut outcomes, &self.recognition_arena);
11283        memo.insert(key, outcomes.clone());
11284        outcomes
11285    }
11286
11287    /// Follows an epsilon or semantic-action transition while preserving the
11288    /// path-local side effects that may later become generated action output.
11289    fn recognize_epsilon_or_action_step(
11290        &mut self,
11291        atn: &Atn,
11292        request: &RecognizeRequest<'_>,
11293        step: EpsilonActionStep,
11294        scratch: RecognizeScratch<'_>,
11295    ) -> Vec<RecognizeOutcome> {
11296        let RecognizeScratch {
11297            visiting,
11298            memo,
11299            expected,
11300        } = scratch;
11301        let action = step.action_rule_index.map(|rule_index| {
11302            let stop_index = self.rule_stop_token_index(request.index, request.consumed_eof);
11303            step.action_index.map_or_else(
11304                || {
11305                    ParserAction::new(
11306                        step.source_state,
11307                        rule_index,
11308                        request.rule_start_index,
11309                        stop_index,
11310                    )
11311                },
11312                |action_index| {
11313                    ParserAction::new_indexed(
11314                        step.source_state,
11315                        rule_index,
11316                        action_index,
11317                        request.rule_start_index,
11318                        stop_index,
11319                    )
11320                },
11321            )
11322        });
11323        let next_member_values = if action.is_some() {
11324            member_values_after_action(
11325                step.source_state,
11326                request.member_actions,
11327                request.semantics,
11328                &request.member_values,
11329            )
11330        } else {
11331            request.member_values.clone()
11332        };
11333        let next_return_values = action.map_or_else(
11334            || request.return_values.clone(),
11335            |action| {
11336                return_values_after_action(
11337                    step.source_state,
11338                    action.rule_index(),
11339                    request.return_actions,
11340                    request.semantics,
11341                    &request.return_values,
11342                )
11343            },
11344        );
11345
11346        self.recognize_state(
11347            atn,
11348            RecognizeRequest {
11349                state_number: step.target,
11350                stop_state: request.stop_state,
11351                index: request.index,
11352                rule_start_index: request.rule_start_index,
11353                decision_start_index: step.decision_start_index,
11354                init_action_rules: request.init_action_rules,
11355                predicates: request.predicates,
11356                semantics: request.semantics,
11357                rule_args: request.rule_args,
11358                member_actions: request.member_actions,
11359                return_actions: request.return_actions,
11360                local_int_arg: request.local_int_arg,
11361                member_values: next_member_values,
11362                return_values: next_return_values,
11363                rule_alt_number: if step.left_recursive_boundary.is_some() {
11364                    0
11365                } else {
11366                    step.alt_number
11367                },
11368                track_alt_numbers: request.track_alt_numbers,
11369                consumed_eof: request.consumed_eof,
11370                committed_decision: request.committed_decision,
11371                precedence: request.precedence,
11372                depth: request.depth + 1,
11373                recovery_symbols: step.recovery_symbols,
11374                recovery_state: step.recovery_state,
11375            },
11376            visiting,
11377            memo,
11378            expected,
11379        )
11380        .into_iter()
11381        .map(|mut outcome| {
11382            prepend_decision(&mut outcome, step.decision);
11383            if let Some(rule_index) = step.left_recursive_boundary {
11384                let boundary = self.arena_boundary_node(rule_index, step.alt_number);
11385                self.arena_prepend(&mut outcome.nodes, boundary);
11386            }
11387            if let Some(action) = action {
11388                outcome.actions.insert(0, action);
11389            }
11390            outcome
11391        })
11392        .collect()
11393    }
11394
11395    /// Reads the token type at an absolute token-stream index without moving
11396    /// the parser's stream cursor. The fast recognizer probes lookahead at
11397    /// every state visit, so avoiding the seek round-trip is a measurable
11398    /// hot-path win on long inputs.
11399    fn token_type_at(&mut self, index: usize) -> i32 {
11400        if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !self.input.is_filled() {
11401            self.input.fill();
11402        }
11403        self.input.token_type_at_index(index)
11404    }
11405
11406    /// Returns the cached `state_expected_symbols` set for an ATN state.
11407    ///
11408    /// The fast recognizer consults this set on every state visit through
11409    /// `next_recovery_context`; the underlying DFS is a pure function of the
11410    /// ATN, so caching the `Rc` lets clones reduce to a reference bump.
11411    ///
11412    /// Caching is layered through `intern_recovery_symbols` so two ATN states
11413    /// with the same expected-symbol set share one `Rc`. That invariant is
11414    /// what lets `FastRecognizeKey` hash on `recovery_symbols` by pointer
11415    /// without violating the `Hash`/`Eq` contract — `recovery_symbols` is
11416    /// always interned before it ends up in a key.
11417    fn cached_state_expected_symbols(
11418        &mut self,
11419        atn: &Atn,
11420        state_number: usize,
11421    ) -> Rc<BTreeSet<i32>> {
11422        if let Some(cached) = self.state_expected_cache.get(&state_number) {
11423            return Rc::clone(cached);
11424        }
11425        let symbols = state_expected_symbols(atn, state_number);
11426        let entry = self.intern_recovery_symbols(symbols);
11427        self.state_expected_cache
11428            .insert(state_number, Rc::clone(&entry));
11429        entry
11430    }
11431
11432    fn cached_state_expected_token_set(
11433        &mut self,
11434        atn: &Atn,
11435        state_number: usize,
11436    ) -> Rc<TokenBitSet> {
11437        if let Some(cached) = self.state_expected_token_cache.get(&state_number) {
11438            return Rc::clone(cached);
11439        }
11440        // Purely a function of the ATN, so back the per-parser cache with the
11441        // thread-shared one — fresh parser instances (one per parse in
11442        // generated usage) start warm instead of rewalking the ATN.
11443        let symbols = with_shared_atn_caches(atn, |cache| {
11444            if let Some(cached) = cache.state_expected_tokens.get(&state_number) {
11445                return Rc::clone(cached);
11446            }
11447            let symbols = Rc::new(state_expected_token_set(atn, state_number));
11448            cache
11449                .state_expected_tokens
11450                .insert(state_number, Rc::clone(&symbols));
11451            symbols
11452        });
11453        self.state_expected_token_cache
11454            .insert(state_number, Rc::clone(&symbols));
11455        symbols
11456    }
11457
11458    fn cached_state_can_reach_rule_stop(&mut self, atn: &Atn, state_number: usize) -> bool {
11459        if self.rule_stop_reach_cache.len() <= state_number {
11460            self.rule_stop_reach_cache
11461                .resize_with(atn.states().len().max(state_number + 1), || None);
11462        }
11463        if let Some(reaches) = self.rule_stop_reach_cache[state_number] {
11464            return reaches;
11465        }
11466        let reaches = with_shared_atn_caches(atn, |cache| {
11467            *cache
11468                .rule_stop_reach
11469                .entry(state_number)
11470                .or_insert_with(|| state_can_reach_rule_stop(atn, state_number))
11471        });
11472        self.rule_stop_reach_cache[state_number] = Some(reaches);
11473        reaches
11474    }
11475
11476    /// Returns the parser's empty `recovery_symbols` singleton so callers can
11477    /// share an `Rc` instead of allocating new `BTreeSet`s for the common case.
11478    fn empty_recovery_symbols(&self) -> Rc<BTreeSet<i32>> {
11479        Rc::clone(&self.empty_recovery_symbols)
11480    }
11481
11482    /// Returns the interned `Rc` form of a `recovery_symbols` set so the fast
11483    /// recognizer can hash and compare keys by pointer.
11484    ///
11485    /// Every `Rc<BTreeSet<i32>>` that flows into a `FastRecognizeKey` must
11486    /// come from this method or the empty singleton; otherwise two
11487    /// content-equal `Rc`s could end up with different `Rc::as_ptr` values,
11488    /// and the pointer-keyed hash on `FastRecognizeKey` would split equivalent
11489    /// recognition coordinates.
11490    fn intern_recovery_symbols(&mut self, set: BTreeSet<i32>) -> Rc<BTreeSet<i32>> {
11491        if set.is_empty() {
11492            return Rc::clone(&self.empty_recovery_symbols);
11493        }
11494        let candidate = Rc::new(set);
11495        match self.recovery_symbols_intern.get(&candidate) {
11496            Some(existing) => Rc::clone(existing),
11497            None => {
11498                self.recovery_symbols_intern
11499                    .insert(Rc::clone(&candidate), Rc::clone(&candidate));
11500                candidate
11501            }
11502        }
11503    }
11504
11505    /// Returns the cached look-1 entry for a decision state, computing it on
11506    /// first use. Multi-alternative states are visited many times during
11507    /// recognition; sharing the entry through `Rc` keeps the prefilter to one
11508    /// hash lookup per visit.
11509    fn cached_decision_lookahead(
11510        &mut self,
11511        atn: &Atn,
11512        state: AtnState<'_>,
11513        rule_stop_state: usize,
11514    ) -> Rc<DecisionLookahead> {
11515        // Hit the parser-instance cache first. Decision lookahead is purely
11516        // a function of the ATN/state, so on a warm cache we skip the
11517        // thread-local + RefCell + HashMap-entry dance through
11518        // SHARED_ATN_CACHES — which on multi-trans-heavy grammars (C# does
11519        // ~58K multi-trans visits per parse) shows up as RefCell borrow and
11520        // hashmap-entry overhead in profiles.
11521        if let Some(cached) = self.decision_lookahead_cache.get(&state.state_number()) {
11522            return Rc::clone(cached);
11523        }
11524        let entry = with_shared_atn_caches(atn, |cache| {
11525            if let Some(cached) = cache.decision_lookahead.get(&state.state_number()) {
11526                return Rc::clone(cached);
11527            }
11528            let mut entry = DecisionLookahead {
11529                transitions: Vec::with_capacity(state.transitions().len()),
11530            };
11531            for transition in &state.transitions() {
11532                entry.transitions.push(transition_first_set(
11533                    atn,
11534                    transition,
11535                    rule_stop_state,
11536                    &mut cache.first_set,
11537                ));
11538            }
11539            let entry = Rc::new(entry);
11540            cache
11541                .decision_lookahead
11542                .insert(state.state_number(), Rc::clone(&entry));
11543            entry
11544        });
11545        self.decision_lookahead_cache
11546            .insert(state.state_number(), Rc::clone(&entry));
11547        entry
11548    }
11549
11550    fn cached_rule_first_set(
11551        &mut self,
11552        atn: &Atn,
11553        target: usize,
11554        child_stop: usize,
11555    ) -> Rc<FirstSet> {
11556        if self.rule_first_set_cache.len() <= target {
11557            self.rule_first_set_cache
11558                .resize_with(atn.states().len().max(target + 1), || None);
11559        }
11560        if let Some(cached) = self
11561            .rule_first_set_cache
11562            .get(target)
11563            .and_then(Option::as_ref)
11564        {
11565            return Rc::clone(cached);
11566        }
11567        let first = with_shared_first_set_cache(atn, |cache| {
11568            rule_first_set(atn, target, child_stop, cache)
11569        });
11570        self.rule_first_set_cache[target] = Some(Rc::clone(&first));
11571        first
11572    }
11573
11574    fn state_can_reenter_without_consuming(&mut self, atn: &Atn, state_number: usize) -> bool {
11575        let atn_key = SharedAtnCacheKey::for_atn(atn);
11576        if self.empty_cycle_cache_atn != Some(atn_key) {
11577            self.empty_cycle_cache.clear();
11578            self.empty_cycle_cache_atn = Some(atn_key);
11579        }
11580        if self.empty_cycle_cache.len() <= state_number {
11581            self.empty_cycle_cache
11582                .resize_with(atn.state_count().max(state_number + 1), || None);
11583        }
11584        if let Some(cached) = self.empty_cycle_cache[state_number] {
11585            return cached;
11586        }
11587        let mut visited = FxHashSet::with_capacity_and_hasher(64, FxBuildHasher::default());
11588        let result = self.empty_path_reaches_state(atn, state_number, state_number, &mut visited);
11589        self.empty_cycle_cache[state_number] = Some(result);
11590        result
11591    }
11592
11593    fn empty_path_reaches_state(
11594        &mut self,
11595        atn: &Atn,
11596        state_number: usize,
11597        target_state: usize,
11598        visited: &mut FxHashSet<usize>,
11599    ) -> bool {
11600        enum Work {
11601            Visit(usize),
11602            RuleFollow {
11603                target: usize,
11604                rule_index: usize,
11605                follow_state: usize,
11606            },
11607        }
11608
11609        let mut work = vec![Work::Visit(state_number)];
11610        while let Some(item) = work.pop() {
11611            match item {
11612                Work::Visit(state_number) => {
11613                    if !visited.insert(state_number) {
11614                        continue;
11615                    }
11616                    let Some(state) = atn.state(state_number) else {
11617                        continue;
11618                    };
11619                    let transitions = state.transitions();
11620                    for transition_index in (0..transitions.len()).rev() {
11621                        let transition = transitions
11622                            .get(transition_index)
11623                            .expect("in-bounds parser transition");
11624                        let kind = transition.kind();
11625                        let target = transition.target();
11626                        match kind {
11627                            ParserTransitionKind::Atom
11628                            | ParserTransitionKind::Range
11629                            | ParserTransitionKind::Set
11630                            | ParserTransitionKind::NotSet
11631                            | ParserTransitionKind::Wildcard => {}
11632                            ParserTransitionKind::Rule => {
11633                                if target == target_state {
11634                                    return true;
11635                                }
11636                                work.push(Work::RuleFollow {
11637                                    target,
11638                                    rule_index: transition.arg0() as usize,
11639                                    follow_state: transition.arg1() as usize,
11640                                });
11641                                work.push(Work::Visit(target));
11642                            }
11643                            ParserTransitionKind::Epsilon
11644                            | ParserTransitionKind::Predicate
11645                            | ParserTransitionKind::Action
11646                            | ParserTransitionKind::Precedence => {
11647                                if target == target_state {
11648                                    return true;
11649                                }
11650                                work.push(Work::Visit(target));
11651                            }
11652                        }
11653                    }
11654                }
11655                Work::RuleFollow {
11656                    target,
11657                    rule_index,
11658                    follow_state,
11659                } => {
11660                    let Some(child_stop) = atn.rule_to_stop_state().get(rule_index) else {
11661                        continue;
11662                    };
11663                    if self.cached_rule_first_set(atn, target, child_stop).nullable {
11664                        if follow_state == target_state {
11665                            return true;
11666                        }
11667                        work.push(Work::Visit(follow_state));
11668                    }
11669                }
11670            }
11671        }
11672        false
11673    }
11674
11675    /// Decides whether the clean recognizer should use its full outcome memo
11676    /// table for this coordinate.
11677    fn clean_memo_enabled_for_key(&mut self, key: &FastRecognizeKey) -> bool {
11678        match self.clean_memo_mode {
11679            CleanMemoMode::Promote => true,
11680            CleanMemoMode::Probe => self.observe_clean_memo_probe(key),
11681            CleanMemoMode::Sparse => {
11682                self.clean_memo_sparse_samples += 1;
11683                if self.clean_memo_sparse_samples < CLEAN_MEMO_REPROBE_INTERVAL {
11684                    return false;
11685                }
11686                self.clean_memo_sparse_samples = 0;
11687                self.clean_memo_mode = CleanMemoMode::Probe;
11688                self.clean_memo_probe_samples = 0;
11689                self.clean_memo_probe_repeats = 0;
11690                self.clean_memo_probe_seen.clear();
11691                self.observe_clean_memo_probe(key)
11692            }
11693        }
11694    }
11695
11696    fn observe_clean_memo_probe(&mut self, key: &FastRecognizeKey) -> bool {
11697        self.clean_memo_probe_samples += 1;
11698        if !self.clean_memo_probe_seen.insert(key.clone()) {
11699            self.clean_memo_probe_repeats += 1;
11700        }
11701        if self.clean_memo_probe_repeats >= CLEAN_MEMO_REPEAT_LIMIT {
11702            self.clean_memo_mode = CleanMemoMode::Promote;
11703            self.clean_memo_probe_seen.clear();
11704            return true;
11705        }
11706        if self.clean_memo_probe_samples >= CLEAN_MEMO_PROBE_LIMIT {
11707            self.clean_memo_mode = CleanMemoMode::Sparse;
11708            self.clean_memo_sparse_samples = 0;
11709            self.clean_memo_probe_seen.clear();
11710            return false;
11711        }
11712        true
11713    }
11714
11715    /// Borrows the visible token at an absolute token-stream index.
11716    fn token_at(&self, index: usize) -> Option<TokenView<'_>> {
11717        self.input.get(index)
11718    }
11719
11720    /// Returns the compact token ID at an absolute token-stream index.
11721    fn token_id_at(&self, index: usize) -> Option<TokenId> {
11722        self.input.get_id(index)
11723    }
11724
11725    fn arena_token_node(&mut self, index: usize, error: bool) -> RecognizedNodeId {
11726        let token = self
11727            .token_id_at(index)
11728            .expect("recognized token index must exist in the token store");
11729        let node = if error {
11730            ArenaRecognizedNode::ErrorToken { token }
11731        } else {
11732            ArenaRecognizedNode::Token { token }
11733        };
11734        self.recognition_arena.push_node(node)
11735    }
11736
11737    fn arena_missing_token_node(
11738        &mut self,
11739        token_type: i32,
11740        at_index: usize,
11741        text: String,
11742    ) -> RecognizedNodeId {
11743        let extra = self
11744            .recognition_arena
11745            .push_extra(RecognitionExtra::MissingToken {
11746                token_type,
11747                at_index: u32::try_from(at_index).expect("missing-token stream index fits in u32"),
11748                text,
11749            });
11750        self.recognition_arena
11751            .push_node(ArenaRecognizedNode::MissingToken { extra })
11752    }
11753
11754    fn arena_rule_node(&mut self, spec: ArenaRuleSpec) -> RecognizedNodeId {
11755        let ArenaRuleSpec {
11756            rule_index,
11757            invoking_state,
11758            alt_number,
11759            start_index,
11760            stop_index,
11761            return_values,
11762            children,
11763        } = spec;
11764        let return_values = (!return_values.is_empty()).then(|| {
11765            self.recognition_arena
11766                .push_extra(RecognitionExtra::ReturnValues(return_values))
11767        });
11768        self.recognition_arena.push_node(ArenaRecognizedNode::Rule {
11769            rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11770            invoking_state: i32::try_from(invoking_state).expect("invoking state fits in i32"),
11771            alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11772            start_index: u32::try_from(start_index).expect("rule start index fits in u32"),
11773            stop_index: stop_index
11774                .map(|index| u32::try_from(index).expect("rule stop index fits in u32")),
11775            return_values,
11776            children,
11777        })
11778    }
11779
11780    fn arena_boundary_node(&mut self, rule_index: usize, alt_number: usize) -> RecognizedNodeId {
11781        self.recognition_arena
11782            .push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
11783                rule_index: u32::try_from(rule_index).expect("rule index fits in u32"),
11784                alt_number: u32::try_from(alt_number).expect("alternative number fits in u32"),
11785            })
11786    }
11787
11788    fn arena_prepend(&mut self, sequence: &mut NodeSeqId, node: RecognizedNodeId) {
11789        *sequence = self.recognition_arena.prepend(*sequence, node);
11790    }
11791
11792    // The perf-counters branch reads the process environment, so this cannot
11793    // become const even when Clippy analyzes the branch-free configuration.
11794    #[allow(clippy::missing_const_for_fn)]
11795    fn finish_recognition_arena(&mut self, root: NodeSeqId, diagnostics: DiagnosticSeqId) {
11796        self.last_recognition_arena_root = root;
11797        self.last_recognition_arena_diagnostics = diagnostics;
11798        #[cfg(feature = "perf-counters")]
11799        if std::env::var("ANTLR_PERF_DUMP").is_ok() {
11800            let stats = self.recognition_arena_stats();
11801            #[allow(clippy::print_stderr)]
11802            {
11803                eprintln!("perf recognition_nodes_total={}", stats.total_nodes);
11804                eprintln!("perf recognition_nodes_live={}", stats.live_nodes);
11805                eprintln!("perf recognition_nodes_dead={}", stats.dead_nodes);
11806                eprintln!("perf recognition_nodes_capacity={}", stats.node_capacity);
11807                eprintln!("perf recognition_links_total={}", stats.total_links);
11808                eprintln!("perf recognition_links_live={}", stats.live_links);
11809                eprintln!("perf recognition_links_dead={}", stats.dead_links);
11810                eprintln!("perf recognition_links_capacity={}", stats.link_capacity);
11811                eprintln!("perf recognition_extras_total={}", stats.total_extras);
11812                eprintln!("perf recognition_extras_live={}", stats.live_extras);
11813                eprintln!("perf recognition_extras_dead={}", stats.dead_extras);
11814                eprintln!("perf recognition_extras_capacity={}", stats.extra_capacity);
11815            }
11816        }
11817    }
11818
11819    fn reset_recognition_arena(&mut self) {
11820        self.recognition_arena.reset();
11821        self.last_recognition_arena_root = NodeSeqId::EMPTY;
11822        self.last_recognition_arena_diagnostics = DiagnosticSeqId::EMPTY;
11823    }
11824
11825    /// Normalizes the current token-stream cursor to the next parser-visible
11826    /// token before capturing a rule start boundary.
11827    fn current_visible_index(&mut self) -> usize {
11828        let index = self.input.index();
11829        self.input.seek(index);
11830        self.input.index()
11831    }
11832
11833    /// Reports whether a child rule reached EOF cleanly while also recording
11834    /// an EOF expectation from a longer path inside that child.
11835    fn child_expected_reaches_clean_eof(
11836        &mut self,
11837        children: &[RecognizeOutcome],
11838        expected: &ExpectedTokens,
11839    ) -> bool {
11840        let Some(index) = expected.index else {
11841            return false;
11842        };
11843        self.token_type_at(index) == TOKEN_EOF
11844            && children
11845                .iter()
11846                .any(|child| child.diagnostics.is_empty() && child.index == index)
11847    }
11848
11849    /// Finds the previous token visible to the parser before `index`.
11850    ///
11851    /// The token stream cursor skips hidden-channel tokens, so subtracting one
11852    /// from a visible-token index can point at whitespace. Parser intervals use
11853    /// this helper to stop at the previous visible token while preserving hidden
11854    /// text inside the rendered interval.
11855    fn previous_token_index(&self, index: usize) -> Option<usize> {
11856        self.input.previous_visible_token_index(index)
11857    }
11858
11859    /// Returns the token-stream index used as a rule stop boundary.
11860    ///
11861    /// EOF transitions keep the cursor on EOF, so a rule that consumed EOF must
11862    /// stop at `index` rather than at the previous visible token.
11863    fn rule_stop_token_index(&mut self, index: usize, consumed_eof: bool) -> Option<usize> {
11864        if consumed_eof && self.token_type_at(index) == TOKEN_EOF {
11865            Some(index)
11866        } else {
11867            self.previous_token_index(index)
11868        }
11869    }
11870
11871    /// Stop-token index for a rule's `@after` action, matching the boundary that
11872    /// `finish_rule` records on the rule context.
11873    ///
11874    /// A rule that matched EOF leaves the cursor parked on the EOF token
11875    /// (`CommonTokenStream::consume` does not advance past EOF), so the stop is
11876    /// the current index rather than the previous visible token. Without this,
11877    /// `$stop`/`$text` in an `@after` action on a rule like `r: a* EOF;` would
11878    /// report the token before EOF (or `None` for empty input), diverging from
11879    /// the rule context that `finish_rule` builds.
11880    ///
11881    /// NOTE: this infers `consumed_eof` from the cursor, which is wrong when a
11882    /// rule ends right before EOF without matching it (the cursor is parked on
11883    /// EOF, but the rule did not consume it). Prefer
11884    /// [`Self::after_action_stop_index_for_tree`], which reuses the stop token the
11885    /// rule context already recorded with the real flag. Kept for callers without
11886    /// the rule tree in hand.
11887    #[must_use]
11888    pub fn after_action_stop_index(&mut self, current_index: usize) -> Option<usize> {
11889        let consumed_eof = self.token_type_at(current_index) == TOKEN_EOF;
11890        self.rule_stop_token_index(current_index, consumed_eof)
11891    }
11892
11893    /// Stop-token index for a rule's `@after` action, taken from the stop token
11894    /// the rule context already recorded.
11895    ///
11896    /// `finish_rule` computes the rule stop with the real `consumed_eof` flag, so
11897    /// reading it back keeps `$stop`/`$text` in an `@after` action aligned with
11898    /// the rule context — even when the rule ends immediately before EOF without
11899    /// matching it (cursor parked on EOF, but `consumed_eof` is false). Falls back
11900    /// to the cursor-based inference only when the tree carries no rule stop.
11901    #[must_use]
11902    pub fn after_action_stop_index_for_tree(
11903        &mut self,
11904        tree: ParseTree,
11905        current_index: usize,
11906    ) -> Option<usize> {
11907        if let Some(stop) = self
11908            .node(tree)
11909            .as_rule()
11910            .and_then(crate::tree::RuleNodeView::stop_id)
11911        {
11912            return Some(stop.index());
11913        }
11914        self.after_action_stop_index(current_index)
11915    }
11916
11917    /// Start-token index for a rule's `@after` action, taken from the start token
11918    /// the rule context already recorded.
11919    ///
11920    /// `enter_rule` sets the rule context start to the first visible token (it
11921    /// skips leading hidden-channel tokens), so reading it back keeps `$start` /
11922    /// `$text` in an `@after` action aligned with the rule context — even when the
11923    /// rule begins after a hidden prefix (e.g. leading whitespace) that the raw
11924    /// pre-rule cursor still points at. Falls back to `fallback_index` only when
11925    /// the tree carries no rule start.
11926    #[must_use]
11927    pub fn after_action_start_index_for_tree(
11928        &self,
11929        tree: ParseTree,
11930        fallback_index: usize,
11931    ) -> usize {
11932        if let Some(start) = self
11933            .node(tree)
11934            .as_rule()
11935            .and_then(crate::tree::RuleNodeView::start_id)
11936        {
11937            return start.index();
11938        }
11939        fallback_index
11940    }
11941
11942    /// Returns the rule stop token for a selected parse path.
11943    ///
11944    /// EOF transitions do not advance the token-stream cursor, so an EOF match
11945    /// must use the current token rather than the previous visible token.
11946    fn rule_stop_token_id(&mut self, index: usize, consumed_eof: bool) -> Option<TokenId> {
11947        self.rule_stop_token_index(index, consumed_eof)
11948            .and_then(|token_index| self.token_id_at(token_index))
11949    }
11950
11951    /// Recovers from a semantic predicate with an ANTLR `<fail='...'>` option.
11952    ///
11953    /// Generated Java reports the failed-predicate message at the current
11954    /// lookahead, then consumes until rule recovery can resume. The metadata
11955    /// runtime models the same visible tree shape by keeping skipped tokens as
11956    /// error nodes and returning from the active rule at EOF.
11957    fn predicate_failure_recovery(
11958        &mut self,
11959        request: PredicateFailureRecovery<'_>,
11960    ) -> RecognizeOutcome {
11961        let PredicateFailureRecovery {
11962            rule_index,
11963            index,
11964            message,
11965            member_values,
11966            return_values,
11967            rule_alt_number,
11968        } = request;
11969        let rule_name = self
11970            .rule_names()
11971            .get(rule_index)
11972            .map_or_else(|| rule_index.to_string(), Clone::clone);
11973        let diagnostic = diagnostic_for_token(
11974            self.token_at(index).as_ref(),
11975            format!("rule {rule_name} {message}"),
11976        );
11977        let mut reversed_nodes = NodeSeqId::EMPTY;
11978        let mut next_index = index;
11979        loop {
11980            let symbol = self.token_type_at(next_index);
11981            if symbol == TOKEN_EOF {
11982                break;
11983            }
11984            let error = self.arena_token_node(next_index, true);
11985            self.arena_prepend(&mut reversed_nodes, error);
11986            let after = self.consume_index(next_index, symbol);
11987            if after == next_index {
11988                break;
11989            }
11990            next_index = after;
11991        }
11992        let nodes = self.recognition_arena.reverse_sequence(reversed_nodes);
11993        let diagnostics = self
11994            .recognition_arena
11995            .prepend_diagnostic(DiagnosticSeqId::EMPTY, diagnostic);
11996        RecognizeOutcome {
11997            index: next_index,
11998            consumed_eof: false,
11999            alt_number: rule_alt_number,
12000            member_values,
12001            return_values,
12002            diagnostics,
12003            decisions: Vec::new(),
12004            actions: Vec::new(),
12005            nodes,
12006        }
12007    }
12008
12009    /// Evaluates a user hook for a predicate coordinate that has no generated
12010    /// runtime table entry.
12011    fn parser_semantic_hook_result(
12012        &mut self,
12013        request: ParserSemanticHookRequest<'_>,
12014    ) -> Option<bool> {
12015        let ParserSemanticHookRequest {
12016            index,
12017            rule_index,
12018            pred_index,
12019            context,
12020            local_int_arg,
12021            member_values,
12022        } = request;
12023        let rule_name = self.rule_names().get(rule_index).cloned();
12024        self.input.seek(index);
12025        let input = &mut self.input;
12026        let semantic_hooks = &mut self.semantic_hooks;
12027        let mut ctx = ParserSemCtx {
12028            input,
12029            tree_storage: &self.tree,
12030            rule_index,
12031            coordinate_index: pred_index,
12032            rule_name,
12033            context,
12034            tree: None,
12035            local_int_arg,
12036            member_values,
12037            action: None,
12038        };
12039        semantic_hooks.sempred(&mut ctx, rule_index, pred_index)
12040    }
12041
12042    /// Re-inserts unknown-predicate coordinates recorded before a nested
12043    /// interpreted recognition, preserving order and skipping any the nested
12044    /// call already recorded, so a generated parent's fail-loud coordinates
12045    /// survive descending into an interpreted child.
12046    fn restore_prior_unknown_predicate_hits(&mut self, prior: Vec<(usize, usize)>) {
12047        if prior.is_empty() {
12048            return;
12049        }
12050        let mut merged = prior;
12051        for coordinate in std::mem::take(&mut self.unknown_predicate_hits) {
12052            if !merged.contains(&coordinate) {
12053                merged.push(coordinate);
12054            }
12055        }
12056        self.unknown_predicate_hits = merged;
12057    }
12058
12059    /// Re-inserts unhandled action coordinates recorded before a nested
12060    /// committed parse so only that child parse's misses affect its result.
12061    fn restore_prior_unhandled_action_hits(&mut self, prior: Vec<(usize, usize)>) {
12062        if prior.is_empty() {
12063            return;
12064        }
12065        let mut merged = prior;
12066        for coordinate in std::mem::take(&mut self.unhandled_action_hits) {
12067            if !merged.contains(&coordinate) {
12068                merged.push(coordinate);
12069            }
12070        }
12071        self.unhandled_action_hits = merged;
12072    }
12073
12074    /// Applies the active [`UnknownSemanticPolicy`] to a predicate coordinate
12075    /// that has no entry in the generated predicate table.
12076    ///
12077    /// Under [`UnknownSemanticPolicy::Error`] the coordinate is recorded and
12078    /// the guarded path is abandoned; the parse entry surfaces the recorded
12079    /// coordinates as [`AntlrError::Unsupported`] once recognition finishes,
12080    /// because a parse that consulted an unknown predicate is unreliable no
12081    /// matter which paths were ultimately selected.
12082    fn unknown_predicate_result(&mut self, rule_index: usize, pred_index: usize) -> bool {
12083        apply_unknown_predicate_policy(
12084            self.unknown_predicate_policy,
12085            rule_index,
12086            pred_index,
12087            &mut self.unknown_predicate_hits,
12088        )
12089    }
12090
12091    /// Builds the fail-loud error for unknown predicate coordinates recorded
12092    /// by the current parse, if any.
12093    fn unknown_semantic_error(&self) -> Option<AntlrError> {
12094        use std::fmt::Write as _;
12095        if self.unknown_predicate_hits.is_empty() && self.unhandled_action_hits.is_empty() {
12096            return None;
12097        }
12098        let mut message = String::new();
12099        for (rule_index, pred_index) in &self.unknown_predicate_hits {
12100            if !message.is_empty() {
12101                message.push_str("; ");
12102            }
12103            let _ = match self.rule_names().get(*rule_index) {
12104                Some(rule_name) => write!(
12105                    message,
12106                    "unsupported semantic predicate: rule={rule_name}({rule_index}) pred_index={pred_index}"
12107                ),
12108                None => write!(
12109                    message,
12110                    "unsupported semantic predicate: rule_index={rule_index} pred_index={pred_index}"
12111                ),
12112            };
12113        }
12114        for (rule_index, source_state) in &self.unhandled_action_hits {
12115            if !message.is_empty() {
12116                message.push_str("; ");
12117            }
12118            let _ = match self.rule_names().get(*rule_index) {
12119                Some(rule_name) => write!(
12120                    message,
12121                    "unhandled semantic action: rule={rule_name}({rule_index}) state={source_state}"
12122                ),
12123                None => write!(
12124                    message,
12125                    "unhandled semantic action: rule_index={rule_index} state={source_state}"
12126                ),
12127            };
12128        }
12129        Some(AntlrError::Unsupported(message))
12130    }
12131
12132    /// Evaluates one lowered predicate expression at the requested input
12133    /// position.
12134    ///
12135    /// This sits in the prediction hot loop, so the context borrows the
12136    /// speculative member state read-only and the rule name by reference —
12137    /// no per-evaluation allocation. Only the hook escape path materializes
12138    /// owned copies, and only when a hook is actually consulted.
12139    fn parser_semir_predicate_matches(
12140        &mut self,
12141        semantics: &ParserSemantics,
12142        predicate: &ParserSemanticPredicate,
12143        request: ParserSemanticHookRequest<'_>,
12144    ) -> bool {
12145        self.input.seek(request.index);
12146        let rule_name = self
12147            .data
12148            .rule_names()
12149            .get(request.rule_index)
12150            .map(String::as_str);
12151        let unknown_predicate_policy = self.unknown_predicate_policy;
12152        let mut ctx = ParserSemIrCtx {
12153            input: &mut self.input,
12154            tree_storage: &self.tree,
12155            semantic_hooks: &mut self.semantic_hooks,
12156            rule_index: request.rule_index,
12157            coordinate_index: request.pred_index,
12158            rule_name,
12159            context: request.context,
12160            local_int_arg: request.local_int_arg,
12161            member_values: request.member_values,
12162            invoked_predicates: &mut self.invoked_predicates,
12163            unknown_predicate_policy,
12164            unknown_predicate_hits: &mut self.unknown_predicate_hits,
12165        };
12166        semir::eval_pred(&semantics.ir, predicate.expr, &mut ctx)
12167    }
12168
12169    fn fast_parser_predicate_matches(
12170        &mut self,
12171        context: Option<FastPredicateContext<'_>>,
12172        transition: ParserTransition<'_>,
12173        index: usize,
12174    ) -> bool {
12175        let Some(context) = context else {
12176            return true;
12177        };
12178        let rule_index = transition.arg0() as usize;
12179        let pred_index = transition.arg1() as usize;
12180        let key = (index, rule_index, pred_index);
12181        if let Some(result) = self.fast_predicate_cache.get(&key) {
12182            return *result;
12183        }
12184        let result = self.parser_predicate_matches(PredicateEval {
12185            index,
12186            rule_index,
12187            pred_index,
12188            predicates: context.predicates,
12189            semantics: context.semantics,
12190            context: None,
12191            local_int_arg: None,
12192            member_values: context.member_values,
12193        });
12194        self.fast_predicate_cache.insert(key, result);
12195        result
12196    }
12197
12198    fn parser_predicate_matches(&mut self, eval: PredicateEval<'_>) -> bool {
12199        let PredicateEval {
12200            index,
12201            rule_index,
12202            pred_index,
12203            predicates,
12204            semantics,
12205            context,
12206            local_int_arg,
12207            member_values,
12208        } = eval;
12209        if let Some((semantics, predicate)) = semantics.and_then(|semantics| {
12210            semantics
12211                .predicates
12212                .iter()
12213                .find(|predicate| {
12214                    predicate.rule_index == rule_index && predicate.pred_index == pred_index
12215                })
12216                .map(|predicate| (semantics, predicate))
12217        }) {
12218            return self.parser_semir_predicate_matches(
12219                semantics,
12220                predicate,
12221                ParserSemanticHookRequest {
12222                    index,
12223                    rule_index,
12224                    pred_index,
12225                    context,
12226                    local_int_arg,
12227                    member_values,
12228                },
12229            );
12230        }
12231        let Some((_, _, predicate)) = predicates
12232            .iter()
12233            .find(|(rule, pred, _)| *rule == rule_index && *pred == pred_index)
12234        else {
12235            if let Some(result) = self.parser_semantic_hook_result(ParserSemanticHookRequest {
12236                index,
12237                rule_index,
12238                pred_index,
12239                context,
12240                local_int_arg,
12241                member_values,
12242            }) {
12243                return result;
12244            }
12245            return self.unknown_predicate_result(rule_index, pred_index);
12246        };
12247        self.input.seek(index);
12248        match predicate {
12249            ParserPredicate::True => true,
12250            ParserPredicate::False => false,
12251            ParserPredicate::FalseWithMessage { .. } => false,
12252            ParserPredicate::Invoke { value } => {
12253                let key = (rule_index, pred_index);
12254                if !self.invoked_predicates.contains(&key) {
12255                    self.invoked_predicates.push(key);
12256                    use std::io::Write as _;
12257                    let mut stdout = std::io::stdout().lock();
12258                    let _ = writeln!(stdout, "eval={value}");
12259                }
12260                *value
12261            }
12262            ParserPredicate::LookaheadTextEquals { offset, text } => self
12263                .input
12264                .lt(*offset)
12265                .is_some_and(|token| Token::text(&token) == Some(*text)),
12266            ParserPredicate::LookaheadNotEquals { offset, token_type } => {
12267                self.la(*offset) != *token_type
12268            }
12269            ParserPredicate::TokenPairAdjacent => {
12270                let Some(first) = self.input.lt_id(-2).map(TokenId::index) else {
12271                    return false;
12272                };
12273                let Some(second) = self.input.lt_id(-1).map(TokenId::index) else {
12274                    return false;
12275                };
12276                first + 1 == second
12277            }
12278            ParserPredicate::ContextChildRuleTextNotEquals { rule_index, text } => context
12279                .and_then(|context| {
12280                    context
12281                        .child_rules(&self.tree, self.input.token_store(), *rule_index)
12282                        .next()
12283                        .map(crate::tree::RuleNodeView::text)
12284                })
12285                .is_none_or(|actual| actual != *text),
12286            ParserPredicate::LocalIntEquals { value } => {
12287                local_int_arg.is_none_or(|(_, actual)| actual == *value)
12288            }
12289            ParserPredicate::LocalIntLessOrEqual { value } => {
12290                local_int_arg.is_none_or(|(_, actual)| actual <= *value)
12291            }
12292            ParserPredicate::MemberModuloEquals {
12293                member,
12294                modulus,
12295                value,
12296                equals,
12297            } => {
12298                if *modulus == 0 {
12299                    return false;
12300                }
12301                let actual = member_values.scalar(*member).unwrap_or_default() % *modulus;
12302                (actual == *value) == *equals
12303            }
12304            ParserPredicate::MemberEquals {
12305                member,
12306                value,
12307                equals,
12308            } => {
12309                let actual = member_values.scalar(*member).unwrap_or_default();
12310                (actual == *value) == *equals
12311            }
12312        }
12313    }
12314
12315    /// Returns a generated fail-option message for a predicate coordinate.
12316    fn parser_predicate_failure_message(
12317        &self,
12318        rule_index: usize,
12319        pred_index: usize,
12320        predicates: &[(usize, usize, ParserPredicate)],
12321    ) -> Option<&'static str> {
12322        predicates
12323            .iter()
12324            .find_map(|(rule, pred, predicate)| match predicate {
12325                ParserPredicate::FalseWithMessage { message }
12326                    if *rule == rule_index && *pred == pred_index =>
12327                {
12328                    Some(*message)
12329                }
12330                _ => None,
12331            })
12332    }
12333
12334    /// Returns a generated fail-option message for a `SemIR` predicate
12335    /// coordinate.
12336    pub fn parser_semantic_ir_predicate_failure_message(
12337        &self,
12338        rule_index: usize,
12339        pred_index: usize,
12340        semantics: &ParserSemantics,
12341    ) -> Option<&'static str> {
12342        semantics
12343            .predicates
12344            .iter()
12345            .find(|predicate| {
12346                predicate.rule_index == rule_index && predicate.pred_index == pred_index
12347            })
12348            .and_then(|predicate| predicate.failure_message)
12349    }
12350
12351    /// Returns the token-stream index after consuming `symbol` at `index`.
12352    ///
12353    /// EOF is not advanced by ANTLR token streams, so EOF transitions keep the
12354    /// index stable and rely on `consumed_eof` to record that EOF was matched.
12355    /// The parser's stream cursor is left untouched: speculative recognition
12356    /// reads ahead by absolute index, so paying for `seek` on every visited
12357    /// state would dominate the hot path. Real consumption is committed by
12358    /// `parse_atn_rule` via `seek` once a viable outcome is selected.
12359    fn consume_index(&mut self, index: usize, symbol: i32) -> usize {
12360        if symbol == TOKEN_EOF {
12361            return index;
12362        }
12363        self.input.next_visible_after(index)
12364    }
12365
12366    /// Builds ANTLR's no-viable-alternative diagnostic for an ambiguous
12367    /// decision that failed after consuming a shared prefix.
12368    fn no_viable_alternative(&self, start_index: usize, error_index: usize) -> ParserDiagnostic {
12369        let text = display_input_text(&self.input.text(start_index, error_index));
12370        diagnostic_for_token(
12371            self.token_at(error_index).as_ref(),
12372            format!("no viable alternative at input '{text}'"),
12373        )
12374    }
12375
12376    /// Selects the diagnostic for a failed consuming transition after all
12377    /// recovery repairs have been ruled out.
12378    fn recovery_failure_diagnostic(
12379        &self,
12380        index: usize,
12381        decision_start_index: Option<usize>,
12382        expected_symbols: &BTreeSet<i32>,
12383    ) -> ParserDiagnostic {
12384        if expected_symbols.len() > 1 {
12385            if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
12386                return self.no_viable_alternative(decision_start, index);
12387            }
12388        }
12389        diagnostic_for_token(
12390            self.token_at(index).as_ref(),
12391            format!(
12392                "mismatched input {} expecting {}",
12393                self.token_at(index)
12394                    .as_ref()
12395                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12396                self.expected_symbols_display(expected_symbols)
12397            ),
12398        )
12399    }
12400
12401    /// Builds the EOF diagnostic used when ANTLR unwinds a failed nested rule
12402    /// instead of inserting missing tokens in the caller.
12403    fn eof_rule_recovery_diagnostic(
12404        &self,
12405        index: usize,
12406        expected_symbols: &BTreeSet<i32>,
12407        expected: &ExpectedTokens,
12408    ) -> ParserDiagnostic {
12409        let symbols = if expected.index == Some(index) && !expected.symbols.is_empty() {
12410            &expected.symbols
12411        } else {
12412            expected_symbols
12413        };
12414        diagnostic_for_token(
12415            self.token_at(index).as_ref(),
12416            format!(
12417                "mismatched input {} expecting {}",
12418                self.token_at(index)
12419                    .as_ref()
12420                    .map_or_else(|| "'<EOF>'".to_owned(), token_input_display),
12421                self.expected_symbols_display(symbols)
12422            ),
12423        )
12424    }
12425
12426    /// Returns token text for a buffered token interval used by generated
12427    /// `$text` actions.
12428    ///
12429    /// ANTLR treats EOF as a range boundary rather than printable input text,
12430    /// even when an action interval explicitly stops at the EOF token.
12431    pub fn text_interval(&self, start: usize, stop: Option<usize>) -> String {
12432        let Some(stop) = stop else {
12433            return String::new();
12434        };
12435        let stop = if self
12436            .token_at(stop)
12437            .is_some_and(|token| token.token_type() == TOKEN_EOF)
12438        {
12439            let Some(previous) = self.previous_token_index(stop) else {
12440                return String::new();
12441            };
12442            previous
12443        } else {
12444            stop
12445        };
12446        self.input.text(start, stop)
12447    }
12448
12449    /// Resets per-parse prediction diagnostics while keeping the parser-level
12450    /// reporting flag configured by generated harness code.
12451    fn clear_prediction_diagnostics(&mut self) {
12452        self.prediction_diagnostics.clear();
12453        self.reported_prediction_diagnostics.clear();
12454    }
12455
12456    /// Drops every per-parse cache that depends on ATN identity or pins
12457    /// recovery-symbol allocations.
12458    ///
12459    /// `BaseParser::parse_atn_rule` takes `&Atn` on each invocation, so the
12460    /// same parser instance can legally be driven against different grammars
12461    /// in sequence. The four caches reset here are keyed by raw ATN
12462    /// coordinates (state numbers, rule indexes) and would silently hand back
12463    /// entries from a previous ATN if reused — pruning lookahead against the
12464    /// wrong transitions or pinning recovery `Rc<BTreeSet<i32>>` allocations
12465    /// for the rest of the process. Clearing them on every parse entry keeps
12466    /// the perf wins (caches still amortize within one parse) without making
12467    /// long-lived parsers leak memory or surface stale ATN data:
12468    ///
12469    /// * `rule_first_set_cache` and `decision_lookahead_cache` are pure
12470    ///   functions of the ATN's state graph.
12471    /// * `state_expected_cache`, `state_expected_token_cache`,
12472    ///   `rule_stop_reach_cache`, and
12473    ///   `recovery_symbols_intern` together form
12474    ///   the identity invariant that lets `FastRecognizeKey` hash
12475    ///   `recovery_symbols` by pointer; they have to be cleared in lockstep
12476    ///   so a stale interned `Rc` cannot outlive its map entry.
12477    /// * `empty_cycle_cache` is grammar-static and carries its own ATN key, so
12478    ///   it is retained here and invalidated lazily when the ATN changes.
12479    fn reset_per_parse_caches(&mut self) {
12480        self.rule_first_set_cache.clear();
12481        self.decision_lookahead_cache.clear();
12482        self.ll1_decision_cache.clear();
12483        self.fast_predicate_cache.clear();
12484        self.rule_stop_reach_cache.clear();
12485        self.clean_memo_mode = CleanMemoMode::Probe;
12486        self.clean_memo_probe_seen.clear();
12487        self.clean_memo_probe_samples = 0;
12488        self.clean_memo_probe_repeats = 0;
12489        self.clean_memo_sparse_samples = 0;
12490        self.recovery_symbols_intern.clear();
12491        self.state_expected_cache.clear();
12492        self.state_expected_token_cache.clear();
12493    }
12494
12495    /// Buffers ANTLR-style diagnostic-listener messages for decision states
12496    /// where multiple clean alternatives survive full-context recognition.
12497    fn record_prediction_diagnostics(
12498        &mut self,
12499        atn: &Atn,
12500        state: AtnState<'_>,
12501        start_index: usize,
12502        outcomes: &[RecognizeOutcome],
12503    ) {
12504        if !self.report_diagnostic_errors || state.transitions().len() < 2 {
12505            return;
12506        }
12507        let Some(decision) = atn
12508            .decision_to_state()
12509            .iter()
12510            .position(|state_number| state_number == state.state_number())
12511        else {
12512            return;
12513        };
12514        let Some(rule_index) = state.rule_index() else {
12515            return;
12516        };
12517        let mut alts_by_end = BTreeMap::<usize, BTreeSet<usize>>::new();
12518        for outcome in outcomes
12519            .iter()
12520            .filter(|outcome| outcome.diagnostics.is_empty())
12521        {
12522            let Some(alt) = outcome.decisions.first() else {
12523                continue;
12524            };
12525            alts_by_end
12526                .entry(outcome.index)
12527                .or_default()
12528                .insert(alt + 1);
12529        }
12530        let Some((&end_index, ambig_alts)) = alts_by_end
12531            .iter()
12532            .filter(|(_, alts)| alts.len() > 1)
12533            .max_by_key(|(end, _)| *end)
12534        else {
12535            return;
12536        };
12537        let rule_name = self
12538            .rule_names()
12539            .get(rule_index)
12540            .map_or_else(|| "<unknown>".to_owned(), Clone::clone);
12541        let stop_index = self.previous_token_index(end_index).unwrap_or(start_index);
12542        let input = display_input_text(&self.input.text(start_index, stop_index));
12543        let alts = ambig_alts
12544            .iter()
12545            .map(usize::to_string)
12546            .collect::<Vec<_>>()
12547            .join(", ");
12548        let key = (decision, start_index, format!("{alts}:{input}"));
12549        if !self.reported_prediction_diagnostics.insert(key) {
12550            return;
12551        }
12552        let start_diagnostic = diagnostic_for_token(
12553            self.token_at(start_index),
12554            format!("reportAttemptingFullContext d={decision} ({rule_name}), input='{input}'"),
12555        );
12556        let stop_diagnostic = diagnostic_for_token(
12557            self.token_at(stop_index),
12558            format!(
12559                "reportAmbiguity d={decision} ({rule_name}): ambigAlts={{{alts}}}, input='{input}'"
12560            ),
12561        );
12562        self.prediction_diagnostics.push(start_diagnostic);
12563        self.prediction_diagnostics.push(stop_diagnostic);
12564    }
12565
12566    /// Formats the tokens expected from an ATN state using ANTLR display names.
12567    pub fn expected_tokens_at_state(&self, atn: &Atn, state_number: usize) -> String {
12568        expected_symbols_display(
12569            &state_expected_symbols(atn, state_number),
12570            self.vocabulary(),
12571        )
12572    }
12573
12574    /// Expected-token set at the parser's current ATN state — ANTLR's
12575    /// `getExpectedTokens()`. Generated recognizers expose this as
12576    /// `self.expected_tokens()` for embedded test actions
12577    /// (`self.expected_tokens().to_token_string(self.vocabulary())`).
12578    pub fn expected_tokens_current(&self, atn: &Atn) -> ExpectedTokenSet {
12579        let state = usize::try_from(self.data().state()).unwrap_or(0);
12580        ExpectedTokenSet {
12581            symbols: state_expected_symbols(atn, state),
12582        }
12583    }
12584
12585    /// Enables the bail error strategy: the first syntax error aborts the
12586    /// parse instead of recovering.
12587    pub const fn set_bail_on_error(&mut self, bail: bool) {
12588        self.bail_on_error = bail;
12589    }
12590
12591    /// Whether the bail error strategy is active.
12592    #[must_use]
12593    pub const fn bail_on_error(&self) -> bool {
12594        self.bail_on_error
12595    }
12596
12597    /// Names of the rules on the live invocation stack, current rule first —
12598    /// ANTLR's `getRuleInvocationStack()`.
12599    pub fn rule_invocation_stack(&self) -> Vec<String> {
12600        self.rule_context_stack
12601            .iter()
12602            .rev()
12603            .map(|frame| {
12604                self.data()
12605                    .rule_names()
12606                    .get(frame.rule_index)
12607                    .cloned()
12608                    .unwrap_or_else(|| format!("<{}>", frame.rule_index))
12609            })
12610            .collect()
12611    }
12612
12613    /// Invoking-state chain for the active rule context, current rule first.
12614    ///
12615    /// The root frame is excluded, matching Java's `RuleContext.toString()`.
12616    pub fn active_invocation_states(&self) -> Vec<isize> {
12617        self.rule_context_stack
12618            .iter()
12619            .skip(1)
12620            .rev()
12621            .map(|frame| frame.invoking_state)
12622            .collect()
12623    }
12624
12625    /// Formats a buffered token in ANTLR's diagnostic token display form.
12626    pub fn token_display_at(&self, index: usize) -> Option<String> {
12627        self.token_at(index).map(|token| format!("{token}"))
12628    }
12629}
12630
12631impl<'atn, S, H> DirectAdaptiveParser<'atn, '_, S, H>
12632where
12633    S: TokenSource,
12634    H: SemanticHooks,
12635{
12636    fn parse_rule(
12637        &mut self,
12638        rule_index: usize,
12639        invoking_state: isize,
12640        precedence: i32,
12641    ) -> DirectAdaptiveParseResult<ParseTree> {
12642        let start_state = self.atn.rule_to_start_state().get(rule_index).ok_or(
12643            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::MissingAtn),
12644        )?;
12645        let stop_state = self
12646            .atn
12647            .rule_to_stop_state()
12648            .get(rule_index)
12649            .filter(|state| *state != usize::MAX)
12650            .ok_or(DirectAdaptiveParseControl::Fallback(
12651                DirectAdaptiveFallback::MissingAtn,
12652            ))?;
12653        let start_index = self.parser.current_visible_index();
12654        let mut context = ParserRuleContext::new(rule_index, invoking_state);
12655        if let Some(token) = self.parser.token_id_at(start_index) {
12656            self.parser.set_context_start(&mut context, token);
12657        }
12658        let mut state_number = start_state;
12659        let mut consumed_eof = false;
12660        while state_number != stop_state {
12661            self.step()?;
12662            let (transition, boundary) = self.next_transition(state_number, precedence)?;
12663            if boundary.is_some() {
12664                return Err(DirectAdaptiveParseControl::Fallback(
12665                    DirectAdaptiveFallback::LeftRecursiveBoundary,
12666                ));
12667            }
12668            match transition.data() {
12669                Transition::Epsilon { target } => {
12670                    state_number = target;
12671                }
12672                Transition::Precedence {
12673                    target,
12674                    precedence: transition_precedence,
12675                } => {
12676                    if transition_precedence < precedence {
12677                        return Err(DirectAdaptiveParseControl::Fallback(
12678                            DirectAdaptiveFallback::Precedence,
12679                        ));
12680                    }
12681                    state_number = target;
12682                }
12683                Transition::Rule {
12684                    rule_index,
12685                    follow_state,
12686                    precedence: rule_precedence,
12687                    ..
12688                } => {
12689                    let child = self.parse_rule(
12690                        rule_index,
12691                        invoking_state_number(state_number),
12692                        rule_precedence,
12693                    )?;
12694                    if self.parser.build_parse_trees {
12695                        self.parser.tree.add_child(&mut context, child);
12696                    }
12697                    state_number = follow_state;
12698                }
12699                Transition::Atom { .. }
12700                | Transition::Range { .. }
12701                | Transition::Set { .. }
12702                | Transition::NotSet { .. }
12703                | Transition::Wildcard { .. } => {
12704                    let (matched_eof, child) = self.consume_transition(transition)?;
12705                    consumed_eof |= matched_eof;
12706                    if let Some(child) = child {
12707                        self.parser.tree.add_child(&mut context, child);
12708                    }
12709                    state_number = transition.target();
12710                }
12711                Transition::Predicate { .. } => {
12712                    return Err(DirectAdaptiveParseControl::Fallback(
12713                        DirectAdaptiveFallback::Predicate,
12714                    ));
12715                }
12716                Transition::Action { .. } => {
12717                    return Err(DirectAdaptiveParseControl::Fallback(
12718                        DirectAdaptiveFallback::Action,
12719                    ));
12720                }
12721            }
12722        }
12723
12724        let stop_index = self
12725            .parser
12726            .rule_stop_token_index(self.parser.input.index(), consumed_eof);
12727        if let Some(token) = stop_index.and_then(|index| self.parser.token_id_at(index)) {
12728            self.parser.set_context_stop(&mut context, token);
12729        }
12730        Ok(self.parser.rule_node(context))
12731    }
12732
12733    const fn step(&mut self) -> DirectAdaptiveParseResult<()> {
12734        self.steps += 1;
12735        if self.steps > ADAPTIVE_DIRECT_STEP_LIMIT {
12736            return Err(DirectAdaptiveParseControl::Fallback(
12737                DirectAdaptiveFallback::StepLimit,
12738            ));
12739        }
12740        Ok(())
12741    }
12742
12743    fn next_transition(
12744        &mut self,
12745        state_number: usize,
12746        precedence: i32,
12747    ) -> DirectAdaptiveParseResult<(ParserTransition<'atn>, Option<usize>)> {
12748        let state = self
12749            .atn
12750            .state(state_number)
12751            .ok_or(DirectAdaptiveParseControl::Fallback(
12752                DirectAdaptiveFallback::MissingAtn,
12753            ))?;
12754        if state.is_rule_stop() {
12755            return Err(DirectAdaptiveParseControl::Fallback(
12756                DirectAdaptiveFallback::RuleStop,
12757            ));
12758        }
12759        let transition_index =
12760            self.transition_index(state_number, state.transitions().len(), precedence)?;
12761        let transition = state.transitions().get(transition_index).ok_or(
12762            DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::NoTransition),
12763        )?;
12764        let boundary = match &transition.data() {
12765            Transition::Epsilon { target } | Transition::Precedence { target, .. } => {
12766                left_recursive_boundary(self.atn, state, *target)
12767            }
12768            _ => None,
12769        };
12770        Ok((transition, boundary))
12771    }
12772
12773    fn transition_index(
12774        &mut self,
12775        state_number: usize,
12776        transition_count: usize,
12777        precedence: i32,
12778    ) -> DirectAdaptiveParseResult<usize> {
12779        match transition_count {
12780            0 => Err(DirectAdaptiveParseControl::Fallback(
12781                DirectAdaptiveFallback::NoTransition,
12782            )),
12783            1 => Ok(0),
12784            _ => {
12785                if let Some(alt) = self.ll1_transition_index(state_number, transition_count)? {
12786                    return Ok(alt);
12787                }
12788                let decision = self
12789                    .decision_by_state
12790                    .get(state_number)
12791                    .and_then(|decision| *decision)
12792                    .ok_or(DirectAdaptiveParseControl::Fallback(
12793                        DirectAdaptiveFallback::UnknownDecision,
12794                    ))?;
12795                let prediction = self
12796                    .simulator
12797                    .adaptive_predict_stream_info_with_precedence(
12798                        decision,
12799                        direct_precedence(precedence),
12800                        &mut self.parser.input,
12801                    )
12802                    .map_err(|_| {
12803                        DirectAdaptiveParseControl::Fallback(DirectAdaptiveFallback::Prediction)
12804                    })?;
12805                if prediction.has_semantic_context {
12806                    return Err(DirectAdaptiveParseControl::Fallback(
12807                        DirectAdaptiveFallback::SemanticContext,
12808                    ));
12809                }
12810                prediction
12811                    .alt
12812                    .checked_sub(1)
12813                    .filter(|index| *index < transition_count)
12814                    .ok_or(DirectAdaptiveParseControl::Fallback(
12815                        DirectAdaptiveFallback::InvalidAlt,
12816                    ))
12817            }
12818        }
12819    }
12820
12821    fn ll1_transition_index(
12822        &mut self,
12823        state_number: usize,
12824        transition_count: usize,
12825    ) -> DirectAdaptiveParseResult<Option<usize>> {
12826        let state = self
12827            .atn
12828            .state(state_number)
12829            .ok_or(DirectAdaptiveParseControl::Fallback(
12830                DirectAdaptiveFallback::MissingAtn,
12831            ))?;
12832        if state.precedence_rule_decision() {
12833            return Ok(None);
12834        }
12835        let Some(rule_stop) = state
12836            .rule_index()
12837            .and_then(|rule_index| self.atn.rule_to_stop_state().get(rule_index))
12838        else {
12839            return Ok(None);
12840        };
12841        let symbol = self.parser.input.la_token(1);
12842        let entry = self
12843            .parser
12844            .cached_decision_lookahead(self.atn, state, rule_stop);
12845        Ok(
12846            ll1_greedy_alt(&entry, symbol, state.non_greedy())
12847                .filter(|alt| *alt < transition_count),
12848        )
12849    }
12850
12851    fn consume_transition(
12852        &mut self,
12853        transition: ParserTransition<'_>,
12854    ) -> DirectAdaptiveParseResult<(bool, Option<ParseTree>)> {
12855        let symbol = self.parser.input.la_token(1);
12856        if !transition.matches(symbol, 1, self.atn.max_token_type()) {
12857            return Err(DirectAdaptiveParseControl::Fallback(
12858                DirectAdaptiveFallback::TokenMismatch,
12859            ));
12860        }
12861        let token = self
12862            .parser
12863            .input
12864            .lt_id(1)
12865            .ok_or(DirectAdaptiveParseControl::Fallback(
12866                DirectAdaptiveFallback::TokenMismatch,
12867            ))?;
12868        let matched_eof = symbol == TOKEN_EOF;
12869        if !matched_eof {
12870            self.parser.consume();
12871        }
12872        let child = self
12873            .parser
12874            .build_parse_trees
12875            .then(|| self.parser.terminal_tree(token));
12876        Ok((matched_eof, child))
12877    }
12878}
12879
12880impl<S, H> CommittedAtnParser<'_, '_, '_, S, H>
12881where
12882    S: TokenSource,
12883    H: SemanticHooks,
12884{
12885    fn parse_rule(
12886        &mut self,
12887        rule_index: usize,
12888        precedence: i32,
12889        inherited_local_int_arg: Option<(usize, i64)>,
12890        init_expected_state: Option<usize>,
12891    ) -> Result<CommittedRuleOutcome, AntlrError> {
12892        let start_state = self
12893            .atn
12894            .rule_to_start_state()
12895            .get(rule_index)
12896            .ok_or_else(|| {
12897                AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
12898            })?;
12899        let stop_state = self
12900            .atn
12901            .rule_to_stop_state()
12902            .get(rule_index)
12903            .filter(|state| *state != usize::MAX)
12904            .ok_or_else(|| {
12905                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
12906            })?;
12907        let left_recursive = self
12908            .atn
12909            .state(start_state)
12910            .is_some_and(AtnState::left_recursive_rule);
12911        if let Some(error) = self.parser.rule_depth_cap_violation() {
12912            return Err(error);
12913        }
12914        if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
12915            return Err(error);
12916        }
12917        let mut context = if left_recursive {
12918            self.parser.enter_recursion_rule(
12919                invoking_state_number(start_state),
12920                rule_index,
12921                precedence,
12922            )
12923        } else {
12924            self.parser
12925                .enter_rule(invoking_state_number(start_state), rule_index)
12926        };
12927        let rule_start_index = self.parser.current_visible_index();
12928        let local_int_arg =
12929            usize::try_from(context.invoking_state())
12930                .ok()
12931                .and_then(|source_state| {
12932                    rule_local_int_arg(
12933                        self.options.rule_args,
12934                        source_state,
12935                        rule_index,
12936                        inherited_local_int_arg,
12937                    )
12938                });
12939        if self.options.init_action_rules.contains(&rule_index) {
12940            let action = ParserAction::new_rule_init(
12941                rule_index,
12942                rule_start_index,
12943                init_expected_state.or(Some(start_state)),
12944            );
12945            if !self
12946                .parser
12947                .parser_rule_init_hook_with_context(action, &context, local_int_arg)
12948            {
12949                self.deferred_actions.push(action);
12950            }
12951        }
12952        let mut consumed_eof = false;
12953        let result = self.walk_rule(
12954            rule_index,
12955            start_state,
12956            stop_state,
12957            precedence,
12958            rule_start_index,
12959            local_int_arg,
12960            left_recursive,
12961            &mut context,
12962            &mut consumed_eof,
12963        );
12964
12965        let result = match result {
12966            Ok(()) => Ok(if left_recursive {
12967                self.parser.finish_recursion_rule(context, consumed_eof)
12968            } else {
12969                self.parser.finish_rule(context, consumed_eof)
12970            }),
12971            Err(error) if self.parser.bail_on_error() => {
12972                if left_recursive {
12973                    self.parser.unroll_recursion_context();
12974                } else {
12975                    self.parser.exit_rule();
12976                }
12977                Err(error)
12978            }
12979            Err(error) => {
12980                self.parser
12981                    .recover_generated_rule(&mut context, self.atn, error);
12982                Ok(if left_recursive {
12983                    self.parser.finish_recursion_rule(context, consumed_eof)
12984                } else {
12985                    self.parser.finish_rule(context, consumed_eof)
12986                })
12987            }
12988        };
12989        self.parser.parse_listener_exit_rule(rule_index);
12990        result.map(|tree| CommittedRuleOutcome { tree, consumed_eof })
12991    }
12992
12993    #[allow(clippy::too_many_arguments)]
12994    fn walk_rule(
12995        &mut self,
12996        rule_index: usize,
12997        mut state_number: usize,
12998        stop_state: usize,
12999        precedence: i32,
13000        rule_start_index: usize,
13001        local_int_arg: Option<(usize, i64)>,
13002        left_recursive: bool,
13003        context: &mut ParserRuleContext,
13004        consumed_eof: &mut bool,
13005    ) -> Result<(), AntlrError> {
13006        let mut entered_loops = BTreeSet::new();
13007        let mut visited_coordinates = FxHashSet::default();
13008        let mut guarded_input_index = self.parser.input.index();
13009        while state_number != stop_state {
13010            let input_index = self.parser.input.index();
13011            if input_index != guarded_input_index {
13012                visited_coordinates.clear();
13013                guarded_input_index = input_index;
13014            }
13015            if !visited_coordinates.insert((state_number, input_index)) {
13016                return Err(AntlrError::Unsupported(format!(
13017                    "committed parser encountered a non-consuming ATN cycle at state \
13018                         {state_number}"
13019                )));
13020            }
13021            let state = self.atn.state(state_number).ok_or_else(|| {
13022                AntlrError::Unsupported(format!("missing parser ATN state {state_number}"))
13023            })?;
13024            if state.is_rule_stop() {
13025                return Err(AntlrError::Unsupported(format!(
13026                    "rule {rule_index} reached unexpected stop state {state_number}"
13027                )));
13028            }
13029            let transition_index = {
13030                let mut decision_context = CommittedDecisionContext {
13031                    precedence,
13032                    local_int_arg,
13033                    context,
13034                    entered_loops: &mut entered_loops,
13035                };
13036                self.transition_index(state, &mut decision_context)?
13037            };
13038            let transition = state.transitions().get(transition_index).ok_or_else(|| {
13039                AntlrError::Unsupported(format!(
13040                    "missing transition {transition_index} from parser ATN state {state_number}"
13041                ))
13042            })?;
13043
13044            let next_alt = next_alt_number(
13045                state,
13046                state.transitions().len(),
13047                transition_index,
13048                context.alt_number(),
13049                self.options.track_alt_numbers,
13050            );
13051            if self.options.track_alt_numbers && context.alt_number() == 0 && next_alt != 0 {
13052                context.set_alt_number(next_alt);
13053            }
13054            let next_context_alt = next_alt_number(
13055                state,
13056                state.transitions().len(),
13057                transition_index,
13058                context.context_alt_number(),
13059                self.options.track_context_alt_numbers,
13060            );
13061            if self.options.track_context_alt_numbers
13062                && context.context_alt_number() == 0
13063                && next_context_alt != 0
13064            {
13065                context.set_context_alt_number(next_context_alt);
13066            }
13067
13068            if left_recursive
13069                && left_recursive_boundary(self.atn, state, transition.target()).is_some()
13070            {
13071                if let Some(error) = self.parser.rule_depth_cap_violation() {
13072                    return Err(error);
13073                }
13074                self.parser.parse_listener_exit_rule(rule_index);
13075                self.parser.push_new_recursion_context_with_previous(
13076                    invoking_state_number(
13077                        self.atn
13078                            .rule_to_start_state()
13079                            .get(rule_index)
13080                            .unwrap_or(state_number),
13081                    ),
13082                    rule_index,
13083                    context,
13084                );
13085                if let Some(error) = self.parser.parse_listener_enter_rule(rule_index) {
13086                    return Err(error);
13087                }
13088            }
13089            state_number = self.apply_transition(
13090                state_number,
13091                transition,
13092                precedence,
13093                rule_start_index,
13094                local_int_arg,
13095                context,
13096                consumed_eof,
13097            )?;
13098        }
13099        Ok(())
13100    }
13101
13102    fn transition_index(
13103        &mut self,
13104        state: AtnState<'_>,
13105        decision_context: &mut CommittedDecisionContext<'_>,
13106    ) -> Result<usize, AntlrError> {
13107        let transition_count = state.transitions().len();
13108        if transition_count == 1 {
13109            return Ok(0);
13110        }
13111        let Some(decision) = self
13112            .decision_by_state
13113            .get(state.state_number())
13114            .copied()
13115            .flatten()
13116        else {
13117            return Err(AntlrError::Unsupported(format!(
13118                "parser ATN state {} has {transition_count} transitions but is not a decision",
13119                state.state_number()
13120            )));
13121        };
13122
13123        let decision_start = self.parser.input.index();
13124        let overridden_transition = if self.parser.semantic_hooks.observes_parser_decisions() {
13125            self.parser
13126                .semantic_hooks
13127                .parser_decision_override(decision, decision_start, transition_count)
13128                .and_then(|alternative| alternative.checked_sub(1))
13129                .filter(|alternative| *alternative < transition_count)
13130        } else {
13131            None
13132        };
13133        if let Some(selected) = overridden_transition {
13134            self.update_loop_selection(state, selected, decision_context);
13135            return Ok(selected);
13136        }
13137
13138        if !state.precedence_rule_decision() {
13139            let loop_back = match state.kind() {
13140                AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack => true,
13141                AtnStateKind::StarLoopEntry => decision_context
13142                    .entered_loops
13143                    .contains(&state.state_number()),
13144                _ => false,
13145            };
13146            let children = self.parser.sync_decision(
13147                self.atn,
13148                state.state_number(),
13149                !decision_context.context.has_matched_child(),
13150                loop_back,
13151            )?;
13152            for child in children {
13153                self.parser.add_parse_child(decision_context.context, child);
13154            }
13155        }
13156
13157        let prediction_precedence = if state.precedence_rule_decision() {
13158            usize::try_from(decision_context.precedence.max(0)).unwrap_or_default()
13159        } else {
13160            0
13161        };
13162        let prediction_context = {
13163            let return_states = self
13164                .parser
13165                .prediction_context_return_states(self.atn)
13166                .collect::<Vec<_>>();
13167            self.simulator
13168                .intern_prediction_context(self.parser.rule_context_version(), return_states)
13169        };
13170        self.simulator.set_exact_ambig_detection(
13171            self.parser.prediction_mode() == PredictionMode::LlExactAmbigDetection,
13172        );
13173        let prediction_mode = self.parser.prediction_mode();
13174        let prediction = match self.simulator.adaptive_predict_stream_info_sll_probe(
13175            decision,
13176            prediction_precedence,
13177            &mut self.parser.input,
13178        ) {
13179            Ok(prediction)
13180                if prediction.requires_full_context && prediction_mode != PredictionMode::Sll =>
13181            {
13182                self.simulator.adaptive_predict_stream_info_with_context(
13183                    decision,
13184                    prediction_precedence,
13185                    &mut self.parser.input,
13186                    prediction_context,
13187                )
13188            }
13189            prediction => prediction,
13190        };
13191        let mut prediction = match prediction {
13192            Ok(prediction) => prediction,
13193            Err(ParserAtnSimulatorError::NoViableAlt { index, .. })
13194                if state.precedence_rule_decision() =>
13195            {
13196                let enter_alt = state.transitions().iter().position(|transition| {
13197                    self.atn
13198                        .state(transition.target())
13199                        .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd)
13200                });
13201                let exit_alt = state.transitions().iter().position(|transition| {
13202                    self.atn
13203                        .state(transition.target())
13204                        .is_some_and(|target| target.kind() == AtnStateKind::LoopEnd)
13205                });
13206                let selected = if self.parser.left_recursive_loop_enter_matches(
13207                    self.atn,
13208                    state.state_number(),
13209                    decision_context.precedence,
13210                ) {
13211                    enter_alt
13212                } else {
13213                    exit_alt
13214                };
13215                let Some(selected) = selected else {
13216                    return Err(self
13217                        .parser
13218                        .no_viable_alternative_error_at(decision_start, index));
13219                };
13220                ParserAtnPrediction {
13221                    alt: selected + 1,
13222                    requires_full_context: true,
13223                    has_semantic_context: true,
13224                    diagnostic: None,
13225                }
13226            }
13227            Err(ParserAtnSimulatorError::NoViableAlt { index, .. }) => {
13228                return Err(self
13229                    .parser
13230                    .no_viable_alternative_error_at(decision_start, index));
13231            }
13232            Err(ParserAtnSimulatorError::PredictionRequiresMoreLookahead) => {
13233                return Err(self.parser.no_viable_alternative_error(decision_start));
13234            }
13235            Err(error) => {
13236                return Err(AntlrError::Unsupported(format!(
13237                    "committed parser prediction failed at decision {decision}: {error:?}"
13238                )));
13239            }
13240        };
13241        let mut selected = prediction
13242            .alt
13243            .checked_sub(1)
13244            .filter(|index| *index < transition_count)
13245            .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13246
13247        let semantic_candidates = self.simulator.prediction_semantic_candidates();
13248        if !semantic_candidates.is_empty() {
13249            let predicted_alt = prediction.alt;
13250            let mut semantic_results = BTreeMap::new();
13251            let selected_alt = selected + 1;
13252            let selected_matches = self.semantic_alternative_matches(
13253                selected_alt,
13254                decision_context,
13255                &semantic_candidates,
13256            );
13257            semantic_results.insert(selected_alt, selected_matches);
13258            if !selected_matches {
13259                let alternatives = semantic_candidates
13260                    .iter()
13261                    .map(|candidate| candidate.alt)
13262                    .filter(|alternative| *alternative != 0 && *alternative <= transition_count)
13263                    .collect::<BTreeSet<_>>();
13264                selected = alternatives
13265                    .into_iter()
13266                    .find(|alternative| {
13267                        let matches = self.semantic_alternative_matches(
13268                            *alternative,
13269                            decision_context,
13270                            &semantic_candidates,
13271                        );
13272                        semantic_results.insert(*alternative, matches);
13273                        matches
13274                    })
13275                    .and_then(|alternative| alternative.checked_sub(1))
13276                    .ok_or_else(|| self.parser.no_viable_alternative_error(decision_start))?;
13277            }
13278            if self.parser.report_diagnostic_errors
13279                && let Some(diagnostic) = prediction.diagnostic.as_ref()
13280            {
13281                for alternative in diagnostic.conflicting_alts.clone() {
13282                    if semantic_results.contains_key(&alternative)
13283                        || !semantic_candidates
13284                            .iter()
13285                            .any(|candidate| candidate.alt == alternative)
13286                    {
13287                        continue;
13288                    }
13289                    let matches = self.semantic_alternative_matches(
13290                        alternative,
13291                        decision_context,
13292                        &semantic_candidates,
13293                    );
13294                    semantic_results.insert(alternative, matches);
13295                }
13296            }
13297            Self::filter_prediction_diagnostic(
13298                &mut prediction,
13299                predicted_alt,
13300                selected + 1,
13301                &semantic_results,
13302            );
13303        }
13304        self.parser.record_generated_prediction_diagnostic(
13305            self.atn,
13306            state.state_number(),
13307            &prediction,
13308        );
13309
13310        self.update_loop_selection(state, selected, decision_context);
13311        Ok(selected)
13312    }
13313
13314    fn semantic_alternative_matches(
13315        &mut self,
13316        alternative: usize,
13317        decision_context: &CommittedDecisionContext<'_>,
13318        candidates: &[ParserSemanticCandidate],
13319    ) -> bool {
13320        candidates
13321            .iter()
13322            .filter(|candidate| candidate.alt == alternative)
13323            .any(|candidate| {
13324                self.semantic_context_matches(&candidate.context, decision_context, candidate)
13325            })
13326    }
13327
13328    fn filter_prediction_diagnostic(
13329        prediction: &mut ParserAtnPrediction,
13330        predicted_alt: usize,
13331        selected_alt: usize,
13332        semantic_results: &BTreeMap<usize, bool>,
13333    ) {
13334        prediction.alt = selected_alt;
13335        if selected_alt != predicted_alt {
13336            prediction.diagnostic = None;
13337            return;
13338        }
13339        if let Some(diagnostic) = prediction.diagnostic.as_mut() {
13340            diagnostic
13341                .conflicting_alts
13342                .retain(|alternative| semantic_results.get(alternative).copied().unwrap_or(true));
13343            if diagnostic.conflicting_alts.len() < 2 {
13344                prediction.diagnostic = None;
13345            }
13346        }
13347    }
13348
13349    fn semantic_context_matches(
13350        &mut self,
13351        semantic_context: &SemanticContext,
13352        decision_context: &CommittedDecisionContext<'_>,
13353        candidate: &ParserSemanticCandidate,
13354    ) -> bool {
13355        match semantic_context {
13356            SemanticContext::None => true,
13357            SemanticContext::Predicate {
13358                rule_index,
13359                pred_index,
13360                ..
13361            } => {
13362                let mut matched_provenance = false;
13363                for predicate_call in candidate
13364                    .predicate_calls
13365                    .iter()
13366                    .filter(|call| call.rule_index == *rule_index && call.pred_index == *pred_index)
13367                {
13368                    matched_provenance = true;
13369                    let mut local_int_arg = decision_context.local_int_arg;
13370                    for rule_call in &predicate_call.rule_calls {
13371                        local_int_arg = rule_local_int_arg(
13372                            self.options.rule_args,
13373                            rule_call.source_state,
13374                            rule_call.rule_index,
13375                            local_int_arg,
13376                        );
13377                    }
13378                    if !self.semantic_predicate_matches(
13379                        *rule_index,
13380                        *pred_index,
13381                        decision_context,
13382                        local_int_arg,
13383                    ) {
13384                        return false;
13385                    }
13386                }
13387                if matched_provenance {
13388                    true
13389                } else {
13390                    self.semantic_predicate_matches(
13391                        *rule_index,
13392                        *pred_index,
13393                        decision_context,
13394                        decision_context.local_int_arg,
13395                    )
13396                }
13397            }
13398            SemanticContext::Precedence { precedence } => {
13399                *precedence >= decision_context.precedence
13400            }
13401            SemanticContext::And(children) => {
13402                for child in children {
13403                    if !self.semantic_context_matches(child, decision_context, candidate) {
13404                        return false;
13405                    }
13406                }
13407                true
13408            }
13409            SemanticContext::Or(children) => {
13410                for child in children {
13411                    if self.semantic_context_matches(child, decision_context, candidate) {
13412                        return true;
13413                    }
13414                }
13415                false
13416            }
13417        }
13418    }
13419
13420    fn semantic_predicate_matches(
13421        &mut self,
13422        rule_index: usize,
13423        pred_index: usize,
13424        decision_context: &CommittedDecisionContext<'_>,
13425        local_int_arg: Option<(usize, i64)>,
13426    ) -> bool {
13427        let member_values = self.parser.int_members.clone();
13428        self.parser.parser_predicate_matches(PredicateEval {
13429            index: self.parser.input.index(),
13430            rule_index,
13431            pred_index,
13432            predicates: self.options.predicates,
13433            semantics: self.options.semantics,
13434            context: Some(&*decision_context.context),
13435            local_int_arg,
13436            member_values: &member_values,
13437        })
13438    }
13439
13440    fn update_loop_selection(
13441        &self,
13442        state: AtnState<'_>,
13443        selected: usize,
13444        decision_context: &mut CommittedDecisionContext<'_>,
13445    ) {
13446        if state.kind() == AtnStateKind::StarLoopEntry {
13447            let enters = self
13448                .atn
13449                .state(
13450                    state
13451                        .transitions()
13452                        .get(selected)
13453                        .expect("selected transition is in bounds")
13454                        .target(),
13455                )
13456                .is_some_and(|target| target.kind() != AtnStateKind::LoopEnd);
13457            if enters {
13458                decision_context.entered_loops.insert(state.state_number());
13459            } else {
13460                decision_context.entered_loops.remove(&state.state_number());
13461            }
13462        }
13463    }
13464
13465    #[allow(clippy::too_many_arguments)]
13466    fn apply_transition(
13467        &mut self,
13468        source_state: usize,
13469        transition: ParserTransition<'_>,
13470        precedence: i32,
13471        rule_start_index: usize,
13472        local_int_arg: Option<(usize, i64)>,
13473        context: &mut ParserRuleContext,
13474        consumed_eof: &mut bool,
13475    ) -> Result<usize, AntlrError> {
13476        self.parser.set_state(invoking_state_number(source_state));
13477        match transition.data() {
13478            Transition::Epsilon { target } => Ok(target),
13479            Transition::Atom { target, label } => {
13480                let matched = self
13481                    .parser
13482                    .match_token_recovering(label, target, self.atn)?;
13483                *consumed_eof |= matched.consumed_eof();
13484                for child in matched.into_child_iter() {
13485                    self.parser.add_parse_child(context, child);
13486                }
13487                Ok(target)
13488            }
13489            Transition::Range {
13490                target,
13491                start,
13492                stop,
13493            } => {
13494                let matched =
13495                    self.parser
13496                        .match_set_recovering(&[(start, stop)], target, self.atn)?;
13497                *consumed_eof |= matched.consumed_eof();
13498                for child in matched.into_child_iter() {
13499                    self.parser.add_parse_child(context, child);
13500                }
13501                Ok(target)
13502            }
13503            Transition::Set { target, set } => {
13504                let matched = self
13505                    .parser
13506                    .match_token_set_recovering(set, target, self.atn)?;
13507                *consumed_eof |= matched.consumed_eof();
13508                for child in matched.into_child_iter() {
13509                    self.parser.add_parse_child(context, child);
13510                }
13511                Ok(target)
13512            }
13513            Transition::NotSet { target, set } => {
13514                let matched = self.parser.match_not_token_set_recovering(
13515                    set,
13516                    1,
13517                    self.atn.max_token_type(),
13518                    target,
13519                    self.atn,
13520                )?;
13521                *consumed_eof |= matched.consumed_eof();
13522                for child in matched.into_child_iter() {
13523                    self.parser.add_parse_child(context, child);
13524                }
13525                Ok(target)
13526            }
13527            Transition::Wildcard { target } => {
13528                let matched = self.parser.match_not_set_recovering(
13529                    &[],
13530                    1,
13531                    self.atn.max_token_type(),
13532                    target,
13533                    self.atn,
13534                )?;
13535                *consumed_eof |= matched.consumed_eof();
13536                for child in matched.into_child_iter() {
13537                    self.parser.add_parse_child(context, child);
13538                }
13539                Ok(target)
13540            }
13541            Transition::Rule {
13542                rule_index,
13543                follow_state,
13544                precedence: rule_precedence,
13545                ..
13546            } => {
13547                let marker = self
13548                    .parser
13549                    .push_invoking_state(invoking_state_number(source_state));
13550                let child = if self.parser.generated_rule_stack_check_due() {
13551                    grow_generated_rule_stack(|| {
13552                        self.parse_rule(
13553                            rule_index,
13554                            rule_precedence,
13555                            local_int_arg,
13556                            Some(follow_state),
13557                        )
13558                    })
13559                } else {
13560                    self.parse_rule(
13561                        rule_index,
13562                        rule_precedence,
13563                        local_int_arg,
13564                        Some(follow_state),
13565                    )
13566                };
13567                self.parser.discard_invoking_state(marker);
13568                let child = child?;
13569                *consumed_eof |= child.consumed_eof;
13570                self.parser.add_parse_child(context, child.tree);
13571                Ok(follow_state)
13572            }
13573            Transition::Predicate {
13574                target,
13575                rule_index,
13576                pred_index,
13577                ..
13578            } => {
13579                let member_values = self.parser.int_members.clone();
13580                if self.parser.parser_predicate_matches(PredicateEval {
13581                    index: self.parser.input.index(),
13582                    rule_index,
13583                    pred_index,
13584                    predicates: self.options.predicates,
13585                    semantics: self.options.semantics,
13586                    context: Some(context),
13587                    local_int_arg,
13588                    member_values: &member_values,
13589                }) {
13590                    return Ok(target);
13591                }
13592                if let Some(message) = self
13593                    .options
13594                    .semantics
13595                    .and_then(|semantics| {
13596                        self.parser.parser_semantic_ir_predicate_failure_message(
13597                            rule_index, pred_index, semantics,
13598                        )
13599                    })
13600                    .or_else(|| {
13601                        self.parser.parser_predicate_failure_message(
13602                            rule_index,
13603                            pred_index,
13604                            self.options.predicates,
13605                        )
13606                    })
13607                {
13608                    return Err(self
13609                        .parser
13610                        .failed_predicate_option_error(rule_index, message));
13611                }
13612                Err(self.parser.failed_predicate_error("semantic predicate"))
13613            }
13614            Transition::Action {
13615                target, rule_index, ..
13616            } => {
13617                self.apply_translated_actions(source_state, rule_index, context);
13618                if let Some(action_index) = self.action_index(source_state) {
13619                    let action = self.parser.parser_action_at_current_indexed(
13620                        source_state,
13621                        rule_index,
13622                        action_index,
13623                        rule_start_index,
13624                        *consumed_eof,
13625                    );
13626                    let _ = self.parser.parser_action_hook_inner(
13627                        action,
13628                        Some(context),
13629                        None,
13630                        local_int_arg,
13631                        true,
13632                    );
13633                }
13634                Ok(target)
13635            }
13636            Transition::Precedence {
13637                target,
13638                precedence: transition_precedence,
13639            } => {
13640                if transition_precedence >= precedence {
13641                    Ok(target)
13642                } else {
13643                    Err(self
13644                        .parser
13645                        .failed_predicate_error(format!("precpred(_ctx, {transition_precedence})")))
13646                }
13647            }
13648        }
13649    }
13650
13651    fn apply_translated_actions(
13652        &mut self,
13653        source_state: usize,
13654        rule_index: usize,
13655        context: &mut ParserRuleContext,
13656    ) {
13657        apply_member_actions(
13658            source_state,
13659            self.options.member_actions,
13660            self.options.semantics,
13661            &mut self.parser.int_members,
13662        );
13663        let return_values = return_values_after_action(
13664            source_state,
13665            rule_index,
13666            self.options.return_actions,
13667            self.options.semantics,
13668            &BTreeMap::new(),
13669        );
13670        for (name, value) in return_values {
13671            context.set_int_return(name, value);
13672        }
13673    }
13674
13675    fn action_index(&self, source_state: usize) -> Option<usize> {
13676        self.action_index_by_state.get(&source_state).copied()
13677    }
13678}
13679
13680/// Detects the loop edge where ANTLR would call `pushNewRecursionContext` for a
13681/// transformed left-recursive rule.
13682fn left_recursive_boundary(atn: &Atn, state: AtnState<'_>, target: usize) -> Option<usize> {
13683    if !state.precedence_rule_decision() {
13684        return None;
13685    }
13686    let target_state = atn.state(target)?;
13687    if target_state.kind() == AtnStateKind::LoopEnd {
13688        return None;
13689    }
13690    state.rule_index()
13691}
13692
13693/// Selects the first outer alternative observed for a rule path.
13694///
13695/// ANTLR's alt-numbered tree contexts store the rule alternative chosen at the
13696/// outer decision. The metadata recognizer only needs this when a generated
13697/// grammar opts into that target template; otherwise the value remains `0` and
13698/// parse-tree rendering is unchanged.
13699fn next_alt_number(
13700    state: AtnState<'_>,
13701    transition_count: usize,
13702    transition_index: usize,
13703    current_alt_number: usize,
13704    track_alt_numbers: bool,
13705) -> usize {
13706    if !track_alt_numbers || current_alt_number != 0 || transition_count <= 1 {
13707        return current_alt_number;
13708    }
13709    if matches!(
13710        state.kind(),
13711        AtnStateKind::Basic
13712            | AtnStateKind::BlockStart
13713            | AtnStateKind::PlusBlockStart
13714            | AtnStateKind::StarBlockStart
13715            | AtnStateKind::StarLoopEntry
13716    ) && !state.precedence_rule_decision()
13717    {
13718        return transition_index + 1;
13719    }
13720    current_alt_number
13721}
13722
13723/// Converts an ATN state number into the signed invoking-state slot used by
13724/// ANTLR parse-tree contexts, saturating only for impossible platform widths.
13725fn invoking_state_number(state_number: usize) -> isize {
13726    isize::try_from(state_number).unwrap_or(isize::MAX)
13727}
13728
13729const fn packed_i32(value: u32) -> i32 {
13730    i32::from_le_bytes(value.to_le_bytes())
13731}
13732
13733fn direct_precedence(precedence: i32) -> usize {
13734    usize::try_from(precedence.max(0)).unwrap_or_default()
13735}
13736
13737fn token_input_display(token: &impl Token) -> String {
13738    format!("'{}'", token.text().unwrap_or("<EOF>"))
13739}
13740
13741fn display_input_text(text: &str) -> String {
13742    let mut out = String::new();
13743    for ch in text.chars() {
13744        match ch {
13745            '\n' => out.push_str("\\n"),
13746            '\r' => out.push_str("\\r"),
13747            '\t' => out.push_str("\\t"),
13748            other => out.push(other),
13749        }
13750    }
13751    out
13752}
13753
13754fn diagnostic_for_token<T: Token>(token: Option<T>, message: String) -> ParserDiagnostic {
13755    let (line, column, offending) = token.map_or((0, 0, None), |token| {
13756        (token.line(), token.column(), Some(token.token_id()))
13757    });
13758    ParserDiagnostic {
13759        line,
13760        column,
13761        message,
13762        offending,
13763    }
13764}
13765
13766fn expected_symbols_display(symbols: &BTreeSet<i32>, vocabulary: &Vocabulary) -> String {
13767    expected_symbols_display_iter(symbols.iter().copied(), vocabulary)
13768}
13769
13770fn expected_symbols_display_iter(
13771    symbols: impl IntoIterator<Item = i32>,
13772    vocabulary: &Vocabulary,
13773) -> String {
13774    let items = symbols
13775        .into_iter()
13776        .map(|symbol| expected_symbol_display(symbol, vocabulary))
13777        .collect::<Vec<_>>();
13778    if let [single] = items.as_slice() {
13779        return single.clone();
13780    }
13781    format!("{{{}}}", items.join(", "))
13782}
13783
13784fn expected_symbol_display(symbol: i32, vocabulary: &Vocabulary) -> String {
13785    if symbol == TOKEN_EOF {
13786        return "<EOF>".to_owned();
13787    }
13788    vocabulary.display_name(symbol)
13789}
13790
13791fn caller_follow_token_info_for_stream<S: TokenSource>(
13792    input: &mut CommonTokenStream<S>,
13793    index: usize,
13794) -> (i32, bool, bool) {
13795    // Generated callers own statement separators; leave them available when
13796    // an interpreted child rule can either stop before or consume one.
13797    if index >= FAST_RECOGNIZER_DEFERRED_FILL_AT && !input.is_filled() {
13798        input.fill();
13799    }
13800    let token_type = input.token_type_at_index(index);
13801    let visible_channel = input.channel();
13802    let token = input.get(index);
13803    let is_boundary = token
13804        .as_ref()
13805        .and_then(Token::text)
13806        .is_some_and(is_caller_follow_boundary_text);
13807    let is_boundary_gap = token.as_ref().is_some_and(|token| {
13808        token.channel() != visible_channel
13809            || is_caller_follow_boundary_gap_text(token.text_or_empty())
13810    });
13811    (token_type, is_boundary, is_boundary_gap)
13812}
13813
13814fn is_caller_follow_boundary_text(text: &str) -> bool {
13815    text.chars().any(|ch| ch == ';' || ch == '\n')
13816        && text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13817}
13818
13819fn is_caller_follow_boundary_gap_text(text: &str) -> bool {
13820    text.chars().all(|ch| ch.is_whitespace() || ch == ';')
13821}
13822
13823/// Returns whether `state` belongs to an ANTLR-transformed left-recursive rule.
13824/// Inline insertion in those precedence loops can synthesize a missing operand
13825/// before an operator and then block the legitimate loop-exit path.
13826fn state_is_left_recursive_rule(atn: &Atn, state: AtnState<'_>) -> bool {
13827    let Some(rule_index) = state.rule_index() else {
13828        return false;
13829    };
13830    atn.rule_to_start_state()
13831        .get(rule_index)
13832        .and_then(|state_number| atn.state(state_number))
13833        .is_some_and(AtnState::left_recursive_rule)
13834}
13835
13836/// Picks the better of two `parse_atn_rule` passes (with and without the
13837/// FIRST-set prefilter). A clean outcome (no diagnostics) always wins over a
13838/// recovered one; among recovered outcomes the second pass is preferred
13839/// because the no-prefilter walk reaches ANTLR-style recovery inside child
13840/// rules. If both passes failed, the second pass's expected-token snapshot
13841/// is returned so the caller renders the same diagnostic ANTLR would.
13842fn select_better_top_outcome(
13843    first: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13844    second: Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens>,
13845    arena: &RecognitionArena,
13846) -> Result<(FastRecognizeOutcome, ExpectedTokens, usize), ExpectedTokens> {
13847    match (first, second) {
13848        (Ok(first), Ok(second)) => {
13849            if arena.diagnostics(first.0.diagnostics).next().is_none() {
13850                Ok(first)
13851            } else {
13852                Ok(second)
13853            }
13854        }
13855        (Ok(first), Err(_)) => Ok(first),
13856        (Err(_), Ok(second)) => Ok(second),
13857        (Err(_), Err(second_expected)) => Err(second_expected),
13858    }
13859}
13860
13861/// Chooses the outermost parse result that consumed the most input.
13862///
13863/// The recognizer intentionally keeps shorter endpoints available while walking
13864/// nested rule transitions so callers can satisfy following tokens such as
13865/// `expr 'and' expr`. Only the public rule entry commits to one endpoint.
13866fn select_best_fast_outcome(
13867    outcomes: impl Iterator<Item = FastRecognizeOutcome>,
13868    prediction_mode: PredictionMode,
13869    caller_follow: Option<&TokenBitSet>,
13870    mut token_info_at: impl FnMut(usize) -> (i32, bool, bool),
13871    arena: &RecognitionArena,
13872) -> Option<FastRecognizeOutcome> {
13873    let mut best = None;
13874    let mut best_caller_follow = None;
13875    for outcome in outcomes {
13876        if matches!(
13877            prediction_mode,
13878            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection
13879        ) && outcome.diagnostics.is_empty()
13880            && let Some(follow) = caller_follow
13881        {
13882            let (token_type, is_boundary, _) = token_info_at(outcome.index);
13883            if is_boundary && follow.contains(token_type) {
13884                let replace =
13885                    best_caller_follow
13886                        .as_ref()
13887                        .is_none_or(|existing: &FastRecognizeOutcome| {
13888                            (outcome.index, outcome.consumed_eof)
13889                                < (existing.index, existing.consumed_eof)
13890                        });
13891                if replace {
13892                    best_caller_follow = Some(outcome);
13893                }
13894            }
13895        }
13896        let Some(existing) = best else {
13897            best = Some(outcome);
13898            continue;
13899        };
13900        let outcome_position = (outcome.index, outcome.consumed_eof);
13901        let best_position = (existing.index, existing.consumed_eof);
13902        let better = match prediction_mode {
13903            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => outcome_is_better(
13904                outcome_position,
13905                outcome.diagnostics,
13906                best_position,
13907                existing.diagnostics,
13908                arena,
13909            ),
13910            PredictionMode::Sll => outcome.index > existing.index,
13911        };
13912        best = Some(if better { outcome } else { existing });
13913    }
13914    let should_use_caller_follow =
13915        best_caller_follow
13916            .as_ref()
13917            .zip(best.as_ref())
13918            .is_some_and(|(candidate, selected)| {
13919                if !selected.diagnostics.is_empty() {
13920                    return true;
13921                }
13922                candidate.index < selected.index
13923                    && (candidate.index..selected.index).all(|index| token_info_at(index).2)
13924            });
13925    if should_use_caller_follow {
13926        best_caller_follow
13927    } else {
13928        best
13929    }
13930}
13931
13932fn select_best_outcome(
13933    outcomes: impl Iterator<Item = RecognizeOutcome>,
13934    prediction_mode: PredictionMode,
13935    arena: &RecognitionArena,
13936) -> Option<RecognizeOutcome> {
13937    let outcomes = outcomes.collect::<Vec<_>>();
13938    let prefer_first_tie = outcomes
13939        .iter()
13940        .any(|outcome| arena.sequence_needs_stable_tie(outcome.nodes));
13941    outcomes.into_iter().reduce(|best, outcome| {
13942        let outcome_position = (outcome.index, outcome.consumed_eof);
13943        let best_position = (best.index, best.consumed_eof);
13944        let better = match prediction_mode {
13945            PredictionMode::Ll | PredictionMode::LlExactAmbigDetection => {
13946                outcome_is_better(
13947                    outcome_position,
13948                    outcome.diagnostics,
13949                    best_position,
13950                    best.diagnostics,
13951                    arena,
13952                ) || (outcome_position == best_position
13953                    && arena.diagnostics_len(outcome.diagnostics)
13954                        == arena.diagnostics_len(best.diagnostics)
13955                    && arena.diagnostics_recovery_rank(outcome.diagnostics)
13956                        == arena.diagnostics_recovery_rank(best.diagnostics)
13957                    && (outcome.decisions < best.decisions
13958                        || (!prefer_first_tie
13959                            && outcome.decisions == best.decisions
13960                            && outcome.actions > best.actions)))
13961            }
13962            PredictionMode::Sll => {
13963                outcome_position > best_position
13964                    || (outcome_position == best_position
13965                        && !prefer_first_tie
13966                        && (outcome.decisions < best.decisions
13967                            || (outcome.decisions == best.decisions
13968                                && outcome_is_better(
13969                                    outcome_position,
13970                                    outcome.diagnostics,
13971                                    best_position,
13972                                    best.diagnostics,
13973                                    arena,
13974                                ))))
13975            }
13976        };
13977        if better {
13978            return outcome;
13979        }
13980        best
13981    })
13982}
13983
13984/// Records the serialized transition order at parser decision states.
13985///
13986/// When two clean paths consume the same input, ANTLR's adaptive prediction
13987/// chooses by alternative order. Keeping this compact trace lets the metadata
13988/// recognizer distinguish greedy and non-greedy optional blocks without a full
13989/// prediction simulator.
13990fn transition_decision(
13991    atn: &Atn,
13992    state: AtnState<'_>,
13993    transition_count: usize,
13994    transition_index: usize,
13995    predicates: &[(usize, usize, ParserPredicate)],
13996) -> Option<usize> {
13997    if transition_count <= 1 || decision_reaches_unsupported_predicate(atn, state, predicates) {
13998        return None;
13999    }
14000    Some(transition_index)
14001}
14002
14003/// Reports whether a state should reset the active no-viable decision start.
14004///
14005/// Loop entry/back states are continuations of the surrounding adaptive
14006/// prediction; resetting at those states would turn LL-star failures back into
14007/// ordinary mismatches.
14008fn starts_prediction_decision(state: AtnState<'_>, transition_count: usize) -> bool {
14009    transition_count > 1
14010        && !matches!(
14011            state.kind(),
14012            AtnStateKind::PlusLoopBack | AtnStateKind::StarLoopBack | AtnStateKind::StarLoopEntry
14013        )
14014}
14015
14016/// Marks a farthest expected-token set as no-viable when multiple alternatives
14017/// failed after the active decision had already consumed input.
14018fn record_no_viable_if_ambiguous(
14019    expected: &mut ExpectedTokens,
14020    decision_start_index: Option<usize>,
14021    index: usize,
14022) {
14023    if expected.index == Some(index) && expected.symbols.len() > 1 {
14024        if let Some(decision_start) = no_viable_decision_start(decision_start_index, index) {
14025            expected.record_no_viable(decision_start, index);
14026        }
14027    }
14028}
14029
14030/// Records a no-viable decision caused by a failed semantic predicate before
14031/// any consuming transition can contribute an expected-token set.
14032const fn record_predicate_no_viable(
14033    expected: &mut ExpectedTokens,
14034    decision_start_index: Option<usize>,
14035    index: usize,
14036) {
14037    if let Some(decision_start) = decision_start_index {
14038        expected.record_no_viable(decision_start, index);
14039    }
14040}
14041
14042/// Returns the active decision start only when the error is past that start.
14043const fn no_viable_decision_start(
14044    decision_start_index: Option<usize>,
14045    index: usize,
14046) -> Option<usize> {
14047    match decision_start_index {
14048        Some(start) if index > start => Some(start),
14049        _ => None,
14050    }
14051}
14052
14053/// Restores expected-token bookkeeping when a child rule found a clean
14054/// consuming path; failures in longer child alternatives should not pollute the
14055/// caller's final expectation set.
14056fn restore_expected(
14057    children: &[RecognizeOutcome],
14058    child_start_index: usize,
14059    expected: &mut ExpectedTokens,
14060    snapshot: ExpectedTokens,
14061    preserve_child_expected: bool,
14062) {
14063    if preserve_child_expected {
14064        return;
14065    }
14066    if children
14067        .iter()
14068        .any(|child| child.diagnostics.is_empty() && child.index > child_start_index)
14069    {
14070        *expected = snapshot;
14071    }
14072}
14073
14074/// Reports whether a decision can reach a predicate the generator did not
14075/// translate. Static alternative order is unsafe for those context predicates.
14076fn decision_reaches_unsupported_predicate(
14077    atn: &Atn,
14078    state: AtnState<'_>,
14079    predicates: &[(usize, usize, ParserPredicate)],
14080) -> bool {
14081    state.transitions().iter().any(|transition| {
14082        transition_reaches_unsupported_predicate(atn, transition, predicates, &mut BTreeSet::new())
14083    })
14084}
14085
14086/// Walks epsilon-like edges from one transition to find unsupported predicates.
14087fn transition_reaches_unsupported_predicate(
14088    atn: &Atn,
14089    transition: ParserTransition<'_>,
14090    predicates: &[(usize, usize, ParserPredicate)],
14091    visited: &mut BTreeSet<usize>,
14092) -> bool {
14093    match &transition.data() {
14094        Transition::Predicate {
14095            rule_index,
14096            pred_index,
14097            ..
14098        } => !predicates
14099            .iter()
14100            .any(|(rule, pred, _)| rule == rule_index && pred == pred_index),
14101        Transition::Epsilon { target }
14102        | Transition::Action { target, .. }
14103        | Transition::Rule { target, .. } => {
14104            state_reaches_unsupported_predicate(atn, *target, predicates, visited)
14105        }
14106        Transition::Precedence { .. }
14107        | Transition::Atom { .. }
14108        | Transition::Range { .. }
14109        | Transition::Set { .. }
14110        | Transition::NotSet { .. }
14111        | Transition::Wildcard { .. } => false,
14112    }
14113}
14114
14115/// Finds an unsupported predicate reachable before a consuming transition.
14116fn state_reaches_unsupported_predicate(
14117    atn: &Atn,
14118    state_number: usize,
14119    predicates: &[(usize, usize, ParserPredicate)],
14120    visited: &mut BTreeSet<usize>,
14121) -> bool {
14122    if !visited.insert(state_number) {
14123        return false;
14124    }
14125    let Some(state) = atn.state(state_number) else {
14126        return false;
14127    };
14128    state.transitions().iter().any(|transition| {
14129        transition_reaches_unsupported_predicate(atn, transition, predicates, visited)
14130    })
14131}
14132
14133/// Adds a decision step to the front of an already-recognized suffix path.
14134fn prepend_decision(outcome: &mut RecognizeOutcome, decision: Option<usize>) {
14135    if let Some(decision) = decision {
14136        outcome.decisions.insert(0, decision);
14137    }
14138}
14139
14140fn outcome_is_better(
14141    outcome_position: (usize, bool),
14142    outcome_diagnostics: DiagnosticSeqId,
14143    best_position: (usize, bool),
14144    best_diagnostics: DiagnosticSeqId,
14145    arena: &RecognitionArena,
14146) -> bool {
14147    let outcome_len = arena.diagnostics_len(outcome_diagnostics);
14148    let best_len = arena.diagnostics_len(best_diagnostics);
14149    outcome_position > best_position
14150        || (outcome_position == best_position
14151            && (outcome_len < best_len
14152                || (outcome_len == best_len
14153                    && arena.diagnostics_recovery_rank(outcome_diagnostics)
14154                        < arena.diagnostics_recovery_rank(best_diagnostics))))
14155}
14156
14157fn discard_recovered_fast_outcomes_if_clean_path_exists(outcomes: &mut Vec<FastRecognizeOutcome>) {
14158    if outcomes
14159        .iter()
14160        .any(|outcome| outcome.diagnostics.is_empty())
14161    {
14162        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14163    }
14164}
14165
14166fn discard_recovered_outcomes_if_clean_path_exists(
14167    outcomes: &mut Vec<RecognizeOutcome>,
14168    arena: &RecognitionArena,
14169) {
14170    if outcomes
14171        .iter()
14172        .any(|outcome| outcome_has_rule_failure_diagnostic(outcome, arena))
14173    {
14174        return;
14175    }
14176    if outcomes
14177        .iter()
14178        .any(|outcome| outcome.diagnostics.is_empty())
14179    {
14180        outcomes.retain(|outcome| outcome.diagnostics.is_empty());
14181    }
14182}
14183
14184/// Reports whether a recovered outcome came from an explicit predicate
14185/// fail-option and therefore should compete with shorter clean loop exits.
14186fn outcome_has_rule_failure_diagnostic(
14187    outcome: &RecognizeOutcome,
14188    arena: &RecognitionArena,
14189) -> bool {
14190    arena
14191        .diagnostics(outcome.diagnostics)
14192        .any(|diagnostic| diagnostic.message.starts_with("rule "))
14193}
14194
14195/// Removes equivalent endpoints before memoizing a state result while
14196/// preserving ATN transition-discovery order.
14197///
14198/// Outcomes are compared on observable recognition state — the input index,
14199/// EOF consumption, and diagnostics — without descending into the parse-tree
14200/// fragment carried by `nodes`. Two paths reaching the same point with
14201/// different node trees would otherwise prevent memoization from collapsing
14202/// equivalent suffixes and explode the speculative-path cache.
14203///
14204/// The first occurrence per recognition key wins, which matches ANTLR's
14205/// greedy alternative selection: serialized ATNs put greedy `*`/`+` loop-back
14206/// transitions before loop-exit, so the first-discovered outcome carries the
14207/// greedy parse-tree fragment.
14208fn dedupe_fast_outcomes(outcomes: &mut Vec<FastRecognizeOutcome>, arena: &RecognitionArena) {
14209    if outcomes.len() < 2 {
14210        return;
14211    }
14212    let mut seen = FxHashSet::with_capacity_and_hasher(outcomes.len(), FxBuildHasher::default());
14213    outcomes.retain(|outcome| {
14214        seen.insert((
14215            outcome.index,
14216            outcome.consumed_eof,
14217            arena.diagnostics_len(outcome.diagnostics),
14218            arena.diagnostics_recovery_rank(outcome.diagnostics),
14219        ))
14220    });
14221}
14222
14223const FAST_OUTCOME_INLINE_KEYS: usize = 8;
14224const FAST_OUTCOME_BITS_PER_WORD: usize = 64;
14225const MAX_FAST_OUTCOME_DENSE_BYTES: usize = 64 * 1024;
14226const MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS: usize = 65_536;
14227
14228#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14229enum FastOutcomeDedupStrategy {
14230    Inline,
14231    Dense,
14232    Sparse,
14233}
14234
14235impl FastOutcomeDedupScratch {
14236    fn prepare_dense(&mut self, word_count: usize) {
14237        while let Some(word_index) = self.touched_dense_words.pop() {
14238            self.dense_words[usize::try_from(word_index).expect("u32 fits in usize")] = 0;
14239        }
14240        if self.dense_words.len() < word_count {
14241            self.dense_words.resize(word_count, 0);
14242        }
14243    }
14244}
14245
14246fn clean_fast_outcome_dense_layout(outcomes: &[FastRecognizeOutcome]) -> Option<(usize, usize)> {
14247    let first_index = outcomes.first()?.index;
14248    let (min_index, max_index) = outcomes[1..].iter().fold(
14249        (first_index, first_index),
14250        |(min_index, max_index), outcome| {
14251            (min_index.min(outcome.index), max_index.max(outcome.index))
14252        },
14253    );
14254    let index_span = max_index.checked_sub(min_index)?.checked_add(1)?;
14255    let bit_count = index_span.checked_mul(2)?;
14256    let word_count =
14257        bit_count.checked_add(FAST_OUTCOME_BITS_PER_WORD - 1)? / FAST_OUTCOME_BITS_PER_WORD;
14258    let dense_bytes = word_count.checked_mul(size_of::<u64>())?;
14259    let sparse_key_bytes = outcomes.len().checked_mul(size_of::<(usize, bool)>())?;
14260    (dense_bytes <= MAX_FAST_OUTCOME_DENSE_BYTES && dense_bytes <= sparse_key_bytes)
14261        .then_some((min_index, word_count))
14262}
14263
14264#[cfg(feature = "perf-counters")]
14265fn record_clean_fast_outcome_dedup(
14266    strategy: FastOutcomeDedupStrategy,
14267    input_len: usize,
14268    output_len: usize,
14269    dense_words: usize,
14270) {
14271    let counter = match strategy {
14272        FastOutcomeDedupStrategy::Inline => &perf_counters::OUTCOME_DEDUPE_INLINE,
14273        FastOutcomeDedupStrategy::Dense => &perf_counters::OUTCOME_DEDUPE_DENSE,
14274        FastOutcomeDedupStrategy::Sparse => &perf_counters::OUTCOME_DEDUPE_SPARSE,
14275    };
14276    perf_counters::inc(
14277        &perf_counters::OUTCOME_DEDUPE_INPUTS,
14278        u64::try_from(input_len).unwrap_or(u64::MAX),
14279    );
14280    perf_counters::inc(
14281        &perf_counters::OUTCOME_DEDUPE_REMOVED,
14282        u64::try_from(input_len - output_len).unwrap_or(u64::MAX),
14283    );
14284    perf_counters::inc(counter, 1);
14285    perf_counters::inc(
14286        &perf_counters::OUTCOME_DEDUPE_DENSE_WORDS,
14287        u64::try_from(dense_words).unwrap_or(u64::MAX),
14288    );
14289}
14290
14291/// Removes duplicate clean endpoints while preserving transition-discovery
14292/// order. Tiny lists stay on the stack; larger compact ranges use a direct
14293/// bitmap, and only wide sparse ranges pay for hashing.
14294fn dedupe_clean_fast_outcomes(
14295    outcomes: &mut Vec<FastRecognizeOutcome>,
14296    scratch: &mut FastOutcomeDedupScratch,
14297) -> FastOutcomeDedupStrategy {
14298    #[cfg(feature = "perf-counters")]
14299    let input_len = outcomes.len();
14300    if outcomes.len() <= FAST_OUTCOME_INLINE_KEYS {
14301        let mut inline_keys = [(0, false); FAST_OUTCOME_INLINE_KEYS];
14302        let mut inline_len = 0_usize;
14303        outcomes.retain(|outcome| {
14304            let key = (outcome.index, outcome.consumed_eof);
14305            if inline_keys[..inline_len].contains(&key) {
14306                return false;
14307            }
14308            inline_keys[inline_len] = key;
14309            inline_len += 1;
14310            true
14311        });
14312        #[cfg(feature = "perf-counters")]
14313        record_clean_fast_outcome_dedup(
14314            FastOutcomeDedupStrategy::Inline,
14315            input_len,
14316            outcomes.len(),
14317            0,
14318        );
14319        return FastOutcomeDedupStrategy::Inline;
14320    }
14321
14322    if let Some((base_index, word_count)) = clean_fast_outcome_dense_layout(outcomes) {
14323        scratch.prepare_dense(word_count);
14324        outcomes.retain(|outcome| {
14325            let bit_index = (outcome.index - base_index) * 2 + usize::from(outcome.consumed_eof);
14326            let word_index = bit_index / FAST_OUTCOME_BITS_PER_WORD;
14327            let bit = 1_u64 << (bit_index % FAST_OUTCOME_BITS_PER_WORD);
14328            let word = &mut scratch.dense_words[word_index];
14329            if *word & bit != 0 {
14330                return false;
14331            }
14332            if *word == 0 {
14333                scratch
14334                    .touched_dense_words
14335                    .push(u32::try_from(word_index).expect("dense outcome bitmap is capped"));
14336            }
14337            *word |= bit;
14338            true
14339        });
14340        #[cfg(feature = "perf-counters")]
14341        record_clean_fast_outcome_dedup(
14342            FastOutcomeDedupStrategy::Dense,
14343            input_len,
14344            outcomes.len(),
14345            word_count,
14346        );
14347        return FastOutcomeDedupStrategy::Dense;
14348    }
14349
14350    scratch.sparse_keys.clear();
14351    scratch.sparse_keys.reserve(outcomes.len());
14352    outcomes.retain(|outcome| {
14353        scratch
14354            .sparse_keys
14355            .insert((outcome.index, outcome.consumed_eof))
14356    });
14357    #[cfg(feature = "perf-counters")]
14358    record_clean_fast_outcome_dedup(
14359        FastOutcomeDedupStrategy::Sparse,
14360        input_len,
14361        outcomes.len(),
14362        0,
14363    );
14364    if scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS {
14365        scratch.sparse_keys = FxHashSet::default();
14366    }
14367    FastOutcomeDedupStrategy::Sparse
14368}
14369
14370/// Sorts and removes equivalent endpoints, including action traces and the
14371/// arena-backed node sequence's structural contents.
14372fn dedupe_outcomes(outcomes: &mut Vec<RecognizeOutcome>, arena: &RecognitionArena) {
14373    outcomes.sort_unstable_by(|left, right| compare_recognize_outcomes(left, right, arena));
14374    outcomes
14375        .dedup_by(|left, right| compare_recognize_outcomes(left, right, arena) == Ordering::Equal);
14376}
14377
14378fn compare_recognize_outcomes(
14379    left: &RecognizeOutcome,
14380    right: &RecognizeOutcome,
14381    arena: &RecognitionArena,
14382) -> Ordering {
14383    left.index
14384        .cmp(&right.index)
14385        .then_with(|| left.consumed_eof.cmp(&right.consumed_eof))
14386        .then_with(|| left.alt_number.cmp(&right.alt_number))
14387        .then_with(|| left.member_values.cmp(&right.member_values))
14388        .then_with(|| left.return_values.cmp(&right.return_values))
14389        .then_with(|| arena.compare_diagnostics(left.diagnostics, right.diagnostics))
14390        .then_with(|| left.decisions.cmp(&right.decisions))
14391        .then_with(|| left.actions.cmp(&right.actions))
14392        .then_with(|| arena.compare_sequences(left.nodes, right.nodes))
14393}
14394
14395impl<S, H> Recognizer for BaseParser<S, H>
14396where
14397    S: TokenSource,
14398    H: SemanticHooks,
14399{
14400    fn data(&self) -> &RecognizerData {
14401        &self.data
14402    }
14403
14404    fn data_mut(&mut self) -> &mut RecognizerData {
14405        &mut self.data
14406    }
14407}
14408
14409impl<S, H> Parser for BaseParser<S, H>
14410where
14411    S: TokenSource,
14412    H: SemanticHooks,
14413{
14414    fn build_parse_trees(&self) -> bool {
14415        self.build_parse_trees
14416    }
14417
14418    fn set_build_parse_trees(&mut self, build: bool) {
14419        self.build_parse_trees = build;
14420    }
14421
14422    fn number_of_syntax_errors(&self) -> usize {
14423        Self::number_of_syntax_errors(self)
14424    }
14425
14426    fn report_diagnostic_errors(&self) -> bool {
14427        self.report_diagnostic_errors
14428    }
14429
14430    fn set_report_diagnostic_errors(&mut self, report: bool) {
14431        self.report_diagnostic_errors = report;
14432    }
14433
14434    fn prediction_mode(&self) -> PredictionMode {
14435        self.prediction_mode
14436    }
14437
14438    fn set_prediction_mode(&mut self, mode: PredictionMode) {
14439        self.prediction_mode = mode;
14440    }
14441
14442    fn max_rule_depth(&self) -> Option<usize> {
14443        self.max_rule_depth
14444    }
14445
14446    fn set_max_rule_depth(&mut self, depth: Option<usize>) {
14447        self.max_rule_depth = depth;
14448    }
14449
14450    fn add_parse_listener(&mut self, listener: Box<dyn ParseListener>) {
14451        self.parse_listeners.push(ParseListenerSlot(listener));
14452    }
14453
14454    fn remove_parse_listeners(&mut self) -> Vec<Box<dyn ParseListener>> {
14455        Self::remove_parse_listeners(self)
14456    }
14457}
14458
14459#[cfg(test)]
14460#[allow(clippy::disallowed_methods)] // `insta` assertion macros unwrap internal I/O.
14461mod tests {
14462    use super::*;
14463    use crate::atn::parser::{
14464        ParserAtnPredictionDiagnostic, ParserAtnPredictionDiagnosticKind, ParserAtnSimulator,
14465    };
14466    use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
14467    use crate::token::{HIDDEN_CHANNEL, Token, TokenId, TokenSink, TokenSpec, TokenStoreError};
14468    use crate::token_stream::CommonTokenStream;
14469    use crate::tree::{NodeKind, ParseTreeStats};
14470    use crate::vocabulary::Vocabulary;
14471    use std::cell::RefCell;
14472    use std::mem::size_of;
14473    use std::rc::Rc;
14474    use std::sync::{Arc, Mutex};
14475
14476    #[test]
14477    fn fx_hasher_write_matches_typed_methods_for_full_words() {
14478        // PR #5 review (Greptile P2): future key types whose `Hash` impl funnels
14479        // bytes through `Hasher::write` (e.g. `String`, `[u8; 8]`, slice-typed
14480        // fields) must hash the same as the typed methods, otherwise an
14481        // `FxHashMap` keyed on such a type silently disagrees with itself
14482        // depending on which entry point the caller used. Verify the
14483        // little-endian word equivalence this PR established.
14484        let value: u64 = 0x0102_0304_0506_0708;
14485        let mut typed = FxHasher::default();
14486        typed.write_u64(value);
14487        let mut bytewise = FxHasher::default();
14488        bytewise.write(&value.to_le_bytes());
14489        assert_eq!(typed.finish(), bytewise.finish());
14490    }
14491
14492    #[derive(Clone, Debug)]
14493    struct TestToken {
14494        spec: TokenSpec,
14495        id: TokenId,
14496        source_name: String,
14497    }
14498
14499    impl TestToken {
14500        fn new(token_type: i32) -> Self {
14501            Self {
14502                spec: TokenSpec::explicit(token_type, ""),
14503                id: TokenId::try_from(0).expect("zero token ID"),
14504                source_name: String::new(),
14505            }
14506        }
14507
14508        fn eof(source_name: &str, index: usize, line: usize, column: usize) -> Self {
14509            Self {
14510                spec: TokenSpec::eof(index, index, line, column),
14511                id: TokenId::try_from(0).expect("zero token ID"),
14512                source_name: source_name.to_owned(),
14513            }
14514        }
14515
14516        fn with_text(mut self, text: impl Into<String>) -> Self {
14517            self.spec.text = Some(text.into());
14518            self
14519        }
14520
14521        const fn with_channel(mut self, channel: i32) -> Self {
14522            self.spec.channel = channel;
14523            self
14524        }
14525
14526        fn with_span(mut self, start: usize, stop: usize) -> Self {
14527            self.spec = self.spec.with_span(start, stop);
14528            self
14529        }
14530
14531        fn with_byte_span(mut self, start: usize, stop: usize) -> Self {
14532            self.spec = self.spec.with_byte_span(start, stop);
14533            self
14534        }
14535
14536        const fn with_position(mut self, line: usize, column: usize) -> Self {
14537            self.spec.line = line;
14538            self.spec.column = column;
14539            self
14540        }
14541
14542        fn set_token_index(&mut self, index: isize) {
14543            self.id = TokenId::try_from(index.max(0).cast_unsigned()).expect("test token index");
14544        }
14545    }
14546
14547    impl Token for TestToken {
14548        fn token_id(&self) -> TokenId {
14549            self.id
14550        }
14551
14552        fn token_type(&self) -> i32 {
14553            self.spec.token_type
14554        }
14555
14556        fn channel(&self) -> i32 {
14557            self.spec.channel
14558        }
14559
14560        fn start(&self) -> usize {
14561            self.spec.start
14562        }
14563
14564        fn stop(&self) -> usize {
14565            self.spec.stop
14566        }
14567
14568        fn line(&self) -> usize {
14569            self.spec.line
14570        }
14571
14572        fn column(&self) -> usize {
14573            self.spec.column
14574        }
14575
14576        fn text(&self) -> Option<&str> {
14577            self.spec.text.as_deref()
14578        }
14579
14580        fn source_name(&self) -> &str {
14581            &self.source_name
14582        }
14583
14584        fn start_byte(&self) -> Option<usize> {
14585            (self.spec.start_byte != usize::MAX).then_some(self.spec.start_byte)
14586        }
14587
14588        fn stop_byte(&self) -> Option<usize> {
14589            (self.spec.stop_byte != usize::MAX).then_some(self.spec.stop_byte)
14590        }
14591    }
14592
14593    #[derive(Debug)]
14594    struct Source {
14595        tokens: Vec<TestToken>,
14596        index: usize,
14597    }
14598
14599    impl TokenSource for Source {
14600        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14601            let token = self
14602                .tokens
14603                .get(self.index)
14604                .cloned()
14605                .unwrap_or_else(|| TestToken::eof("parser-test", self.index, 1, self.index));
14606            self.index += 1;
14607            sink.push(token.spec)
14608        }
14609
14610        fn line(&self) -> usize {
14611            1
14612        }
14613
14614        fn column(&self) -> usize {
14615            self.index
14616        }
14617
14618        fn source_name(&self) -> &'static str {
14619            "parser-test"
14620        }
14621    }
14622
14623    #[derive(Clone, Debug, Eq, PartialEq)]
14624    struct RecordedDiagnostic {
14625        grammar_file_name: String,
14626        offending_text: Option<String>,
14627        line: usize,
14628        column: usize,
14629        span: Option<std::ops::Range<usize>>,
14630        message: String,
14631        error: Option<AntlrError>,
14632    }
14633
14634    #[derive(Clone, Debug)]
14635    struct RecordingErrorListener {
14636        diagnostics: Arc<Mutex<Vec<RecordedDiagnostic>>>,
14637    }
14638
14639    impl<R> crate::ErrorListener<R> for RecordingErrorListener
14640    where
14641        R: Recognizer + ?Sized,
14642    {
14643        fn syntax_error(&mut self, recognizer: &R, event: &SyntaxErrorEvent<'_>) {
14644            self.diagnostics
14645                .lock()
14646                .expect("recorded diagnostics lock")
14647                .push(RecordedDiagnostic {
14648                    grammar_file_name: recognizer.grammar_file_name().to_owned(),
14649                    offending_text: event
14650                        .offending
14651                        .and_then(|token| token.text().map(str::to_owned)),
14652                    line: event.line,
14653                    column: event.column,
14654                    span: event.span.clone(),
14655                    message: event.message.to_owned(),
14656                    error: event.error.cloned(),
14657                });
14658        }
14659    }
14660
14661    #[derive(Debug)]
14662    struct ReportingSource {
14663        source: Source,
14664        diagnostics: Rc<RefCell<Vec<TokenSourceError>>>,
14665    }
14666
14667    impl TokenSource for ReportingSource {
14668        fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
14669            self.source.next_token(sink)
14670        }
14671
14672        fn line(&self) -> usize {
14673            self.source.line()
14674        }
14675
14676        fn column(&self) -> usize {
14677            self.source.column()
14678        }
14679
14680        fn source_name(&self) -> &str {
14681            self.source.source_name()
14682        }
14683
14684        fn report_error(&self, error: &TokenSourceError) -> bool {
14685            self.diagnostics.borrow_mut().push(error.clone());
14686            true
14687        }
14688    }
14689
14690    fn mini_parser_data() -> RecognizerData {
14691        RecognizerData::new(
14692            "Mini.g4",
14693            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
14694        )
14695        .with_rule_names(["s"])
14696    }
14697
14698    fn mini_parser(tokens: Vec<TestToken>) -> BaseParser<Source> {
14699        let data = mini_parser_data();
14700        BaseParser::new(CommonTokenStream::new(Source { tokens, index: 0 }), data)
14701    }
14702
14703    fn mini_parser_with_hooks<H>(tokens: Vec<TestToken>, hooks: H) -> BaseParser<Source, H>
14704    where
14705        H: SemanticHooks,
14706    {
14707        BaseParser::with_semantic_hooks(
14708            CommonTokenStream::new(Source { tokens, index: 0 }),
14709            mini_parser_data(),
14710            hooks,
14711        )
14712    }
14713
14714    #[test]
14715    fn parser_dispatches_recovery_diagnostics_through_registered_listeners() {
14716        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
14717        parser.remove_error_listeners();
14718        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14719        parser.add_error_listener(RecordingErrorListener {
14720            diagnostics: Arc::clone(&diagnostics),
14721        });
14722        let parser_diagnostics = [ParserDiagnostic {
14723            line: 1,
14724            column: 2,
14725            message: "missing 'x' at 'y'".to_owned(),
14726            offending: None,
14727        }];
14728        let token_errors = [
14729            TokenSourceError::new(1, 1, "token recognition error at: '@'").with_span(1..2),
14730            TokenSourceError::new(1, 3, "token recognition error at: '#'").with_span(3..4),
14731        ];
14732
14733        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14734
14735        // The interleaved token/parser diagnostic stream (ordering, columns, messages) is one
14736        // reviewable snapshot instead of three hand-written RecordedDiagnostic literals.
14737        insta::assert_debug_snapshot!(
14738            "parser_dispatches_recovery_diagnostics_through_registered_listeners",
14739            *diagnostics.lock().expect("recorded diagnostics lock")
14740        );
14741
14742        parser.remove_error_listeners();
14743        parser.dispatch_generated_diagnostics(&parser_diagnostics, &token_errors);
14744        assert_eq!(
14745            diagnostics.lock().expect("recorded diagnostics lock").len(),
14746            3
14747        );
14748    }
14749
14750    #[test]
14751    fn recovery_diagnostics_expose_the_offending_token_to_listeners() {
14752        let mut parser = mini_parser(vec![
14753            TestToken::new(7)
14754                .with_text("oops")
14755                .with_span(0, 3)
14756                .with_byte_span(0, 4)
14757                .with_position(1, 2),
14758            TestToken::eof("parser-test", 4, 1, 6),
14759        ]);
14760        parser.remove_error_listeners();
14761        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14762        parser.add_error_listener(RecordingErrorListener {
14763            diagnostics: Arc::clone(&diagnostics),
14764        });
14765        let offending = parser.input.lt_id(1);
14766        assert!(offending.is_some(), "current token should be buffered");
14767        let parser_diagnostics = [ParserDiagnostic {
14768            line: 1,
14769            column: 2,
14770            message: "extraneous input 'oops'".to_owned(),
14771            offending,
14772        }];
14773
14774        parser.dispatch_generated_diagnostics(&parser_diagnostics, &[]);
14775
14776        // Listeners receive a resolvable view of the offending token — the
14777        // ANTLR offendingSymbol contract downstream span-building error
14778        // reporters (miette-style byte-offset underlines) rely on.
14779        let recorded = diagnostics
14780            .lock()
14781            .expect("recorded diagnostics lock")
14782            .clone();
14783        insta::assert_debug_snapshot!(
14784            "recovery_diagnostics_expose_the_offending_token_to_listeners",
14785            recorded
14786        );
14787    }
14788
14789    #[test]
14790    fn recovery_diagnostics_preserve_unknown_custom_token_span() {
14791        let mut parser = mini_parser(vec![
14792            TestToken::new(7)
14793                .with_text("oops")
14794                .with_span(0, 3)
14795                .with_position(1, 2),
14796            TestToken::eof("parser-test", 4, 1, 6),
14797        ]);
14798        parser.remove_error_listeners();
14799        let diagnostics = Arc::new(Mutex::new(Vec::new()));
14800        parser.add_error_listener(RecordingErrorListener {
14801            diagnostics: Arc::clone(&diagnostics),
14802        });
14803        let offending = parser.input.lt_id(1);
14804        assert!(offending.is_some(), "current token should be buffered");
14805
14806        parser.dispatch_parser_diagnostic(&ParserDiagnostic {
14807            line: 1,
14808            column: 2,
14809            message: "extraneous input 'oops'".to_owned(),
14810            offending,
14811        });
14812
14813        let span = {
14814            let diagnostics = diagnostics.lock().expect("recorded diagnostics lock");
14815            assert_eq!(diagnostics.len(), 1);
14816            diagnostics[0].span.clone()
14817        };
14818        assert_eq!(span, None);
14819    }
14820
14821    #[test]
14822    fn parser_leaves_token_errors_to_source_owned_listeners() {
14823        let source_diagnostics = Rc::new(RefCell::new(Vec::new()));
14824        let source = ReportingSource {
14825            source: Source {
14826                tokens: vec![TestToken::eof("parser-test", 0, 1, 0)],
14827                index: 0,
14828            },
14829            diagnostics: Rc::clone(&source_diagnostics),
14830        };
14831        let mut parser = BaseParser::new(CommonTokenStream::new(source), mini_parser_data());
14832        parser.remove_error_listeners();
14833        let parser_diagnostics = Arc::new(Mutex::new(Vec::new()));
14834        parser.add_error_listener(RecordingErrorListener {
14835            diagnostics: Arc::clone(&parser_diagnostics),
14836        });
14837        let source_error = TokenSourceError::new(2, 4, "token recognition error at: '$'");
14838
14839        parser.dispatch_token_source_errors(std::slice::from_ref(&source_error));
14840
14841        assert_eq!(*source_diagnostics.borrow(), [source_error]);
14842        assert!(
14843            parser_diagnostics
14844                .lock()
14845                .expect("recorded diagnostics lock")
14846                .is_empty()
14847        );
14848    }
14849
14850    fn finish_atn(builder: ParserAtnBuilder) -> Atn {
14851        builder.finish().expect("valid packed parser ATN")
14852    }
14853
14854    fn nested_rule_chain_atn(depth: usize) -> Atn {
14855        nested_rule_graph_atn(depth, false, false)
14856    }
14857
14858    fn nested_rule_graph_atn(depth: usize, branching: bool, consuming_follows: bool) -> Atn {
14859        assert!(depth > 0);
14860        let mut atn = ParserAtnBuilder::new(2);
14861        let mut starts = Vec::with_capacity(depth);
14862        let mut stops = Vec::with_capacity(depth);
14863        let mut follows = Vec::with_capacity(depth.saturating_sub(1));
14864        for rule_index in 0..depth {
14865            starts.push(
14866                atn.add_state(AtnStateKind::RuleStart, Some(rule_index))
14867                    .expect("rule start")
14868                    .index(),
14869            );
14870        }
14871        for rule_index in 0..depth {
14872            stops.push(
14873                atn.add_state(AtnStateKind::RuleStop, Some(rule_index))
14874                    .expect("rule stop")
14875                    .index(),
14876            );
14877        }
14878        if consuming_follows {
14879            for rule_index in 0..depth - 1 {
14880                follows.push(
14881                    atn.add_state(AtnStateKind::Basic, Some(rule_index))
14882                        .expect("rule follow")
14883                        .index(),
14884                );
14885            }
14886        }
14887        atn.set_rule_to_start_state(starts.clone())
14888            .expect("rule start states");
14889        atn.set_rule_to_stop_state(stops.clone())
14890            .expect("rule stop states");
14891        for rule_index in 0..depth - 1 {
14892            let follow_state = if consuming_follows {
14893                follows[rule_index]
14894            } else {
14895                stops[rule_index]
14896            };
14897            atn.add_transition(
14898                starts[rule_index],
14899                ParserTransitionSpec::Rule {
14900                    target: starts[rule_index + 1],
14901                    rule_index: rule_index + 1,
14902                    follow_state,
14903                    precedence: 0,
14904                },
14905            )
14906            .expect("nested rule transition");
14907            if branching {
14908                atn.add_transition(
14909                    starts[rule_index],
14910                    ParserTransitionSpec::Atom {
14911                        target: stops[rule_index],
14912                        label: 2,
14913                    },
14914                )
14915                .expect("dead branch transition");
14916            }
14917            if consuming_follows {
14918                atn.add_transition(
14919                    follow_state,
14920                    ParserTransitionSpec::Atom {
14921                        target: stops[rule_index],
14922                        label: 1,
14923                    },
14924                )
14925                .expect("consuming follow transition");
14926            }
14927        }
14928        let token_set = atn.add_interval_set([(1, 1)]).expect("token set");
14929        atn.add_transition(
14930            starts[depth - 1],
14931            ParserTransitionSpec::Set {
14932                target: stops[depth - 1],
14933                set: token_set,
14934            },
14935        )
14936        .expect("terminal set transition");
14937        if branching {
14938            atn.add_transition(
14939                starts[depth - 1],
14940                ParserTransitionSpec::Atom {
14941                    target: stops[depth - 1],
14942                    label: 2,
14943                },
14944            )
14945            .expect("dead leaf branch transition");
14946        }
14947        finish_atn(atn)
14948    }
14949
14950    fn ordinary_star_loop_atn() -> Atn {
14951        let mut atn = ParserAtnBuilder::new(2);
14952        for (state_number, kind, rule_index) in [
14953            (0, AtnStateKind::RuleStart, 0),
14954            (1, AtnStateKind::StarLoopEntry, 0),
14955            (2, AtnStateKind::Basic, 0),
14956            (3, AtnStateKind::StarLoopBack, 0),
14957            (4, AtnStateKind::LoopEnd, 0),
14958            (5, AtnStateKind::Basic, 0),
14959            (6, AtnStateKind::RuleStop, 0),
14960            (7, AtnStateKind::RuleStart, 1),
14961            (8, AtnStateKind::Basic, 1),
14962            (9, AtnStateKind::RuleStop, 1),
14963        ] {
14964            assert_eq!(
14965                atn.add_state(kind, Some(rule_index))
14966                    .expect("state")
14967                    .index(),
14968                state_number
14969            );
14970        }
14971        atn.set_rule_to_start_state(vec![0, 7])
14972            .expect("rule start states");
14973        atn.set_rule_to_stop_state(vec![6, 9])
14974            .expect("rule stop states");
14975        atn.add_decision_state(1).expect("decision state");
14976        atn.set_loop_back_state(4, 3).expect("loop back state");
14977        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
14978            .expect("transition");
14979        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
14980            .expect("transition");
14981        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
14982            .expect("transition");
14983        atn.add_transition(
14984            2,
14985            ParserTransitionSpec::Rule {
14986                target: 7,
14987                rule_index: 1,
14988                follow_state: 3,
14989                precedence: 0,
14990            },
14991        )
14992        .expect("transition");
14993        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 1 })
14994            .expect("transition");
14995        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
14996            .expect("transition");
14997        atn.add_transition(
14998            5,
14999            ParserTransitionSpec::Atom {
15000                target: 6,
15001                label: TOKEN_EOF,
15002            },
15003        )
15004        .expect("transition");
15005        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
15006            .expect("transition");
15007        atn.add_transition(
15008            8,
15009            ParserTransitionSpec::Atom {
15010                target: 9,
15011                label: 1,
15012            },
15013        )
15014        .expect("transition");
15015        finish_atn(atn)
15016    }
15017
15018    /// ATN for `s : (X | X X)* EOF`.
15019    fn ambiguous_ordinary_star_loop_atn() -> Atn {
15020        let mut atn = ParserAtnBuilder::new(1);
15021        for (state_number, kind) in [
15022            (0, AtnStateKind::RuleStart),
15023            (1, AtnStateKind::StarLoopEntry),
15024            (2, AtnStateKind::StarBlockStart),
15025            (3, AtnStateKind::Basic),
15026            (4, AtnStateKind::BlockEnd),
15027            (5, AtnStateKind::StarLoopBack),
15028            (6, AtnStateKind::LoopEnd),
15029            (7, AtnStateKind::Basic),
15030            (8, AtnStateKind::RuleStop),
15031        ] {
15032            assert_eq!(
15033                atn.add_state(kind, Some(0)).expect("state").index(),
15034                state_number
15035            );
15036        }
15037        atn.set_rule_to_start_state(vec![0])
15038            .expect("rule start states");
15039        atn.set_rule_to_stop_state(vec![8])
15040            .expect("rule stop states");
15041        atn.set_end_state(2, 4).expect("block end state");
15042        atn.set_loop_back_state(6, 5).expect("loop back state");
15043        atn.add_decision_state(1).expect("decision state");
15044        atn.add_decision_state(2).expect("decision state");
15045        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15046            .expect("transition");
15047        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15048            .expect("transition");
15049        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
15050            .expect("transition");
15051        atn.add_transition(
15052            2,
15053            ParserTransitionSpec::Atom {
15054                target: 4,
15055                label: 1,
15056            },
15057        )
15058        .expect("transition");
15059        atn.add_transition(
15060            2,
15061            ParserTransitionSpec::Atom {
15062                target: 3,
15063                label: 1,
15064            },
15065        )
15066        .expect("transition");
15067        atn.add_transition(
15068            3,
15069            ParserTransitionSpec::Atom {
15070                target: 4,
15071                label: 1,
15072            },
15073        )
15074        .expect("transition");
15075        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15076            .expect("transition");
15077        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 1 })
15078            .expect("transition");
15079        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15080            .expect("transition");
15081        atn.add_transition(
15082            7,
15083            ParserTransitionSpec::Atom {
15084                target: 8,
15085                label: TOKEN_EOF,
15086            },
15087        )
15088        .expect("transition");
15089        finish_atn(atn)
15090    }
15091
15092    fn ordinary_plus_loop_atn() -> Atn {
15093        let mut atn = ParserAtnBuilder::new(2);
15094        for (state_number, kind, rule_index) in [
15095            (0, AtnStateKind::RuleStart, 0),
15096            (1, AtnStateKind::Basic, 0),
15097            (2, AtnStateKind::PlusLoopBack, 0),
15098            (3, AtnStateKind::LoopEnd, 0),
15099            (4, AtnStateKind::Basic, 0),
15100            (5, AtnStateKind::RuleStop, 0),
15101            (6, AtnStateKind::RuleStart, 1),
15102            (7, AtnStateKind::Basic, 1),
15103            (8, AtnStateKind::RuleStop, 1),
15104        ] {
15105            assert_eq!(
15106                atn.add_state(kind, Some(rule_index))
15107                    .expect("state")
15108                    .index(),
15109                state_number
15110            );
15111        }
15112        atn.set_rule_to_start_state(vec![0, 6])
15113            .expect("rule start states");
15114        atn.set_rule_to_stop_state(vec![5, 8])
15115            .expect("rule stop states");
15116        atn.add_decision_state(2).expect("decision state");
15117        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15118            .expect("transition");
15119        atn.add_transition(
15120            1,
15121            ParserTransitionSpec::Rule {
15122                target: 6,
15123                rule_index: 1,
15124                follow_state: 2,
15125                precedence: 0,
15126            },
15127        )
15128        .expect("transition");
15129        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 1 })
15130            .expect("transition");
15131        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15132            .expect("transition");
15133        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
15134            .expect("transition");
15135        atn.add_transition(
15136            4,
15137            ParserTransitionSpec::Atom {
15138                target: 5,
15139                label: TOKEN_EOF,
15140            },
15141        )
15142        .expect("transition");
15143        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15144            .expect("transition");
15145        atn.add_transition(
15146            7,
15147            ParserTransitionSpec::Atom {
15148                target: 8,
15149                label: 1,
15150            },
15151        )
15152        .expect("transition");
15153        finish_atn(atn)
15154    }
15155
15156    fn repeated_x_tokens(count: usize) -> Vec<TestToken> {
15157        let mut tokens = (0..count)
15158            .map(|_| TestToken::new(1).with_text("x"))
15159            .collect::<Vec<_>>();
15160        tokens.push(TestToken::eof("parser-test", count, 1, count));
15161        tokens
15162    }
15163
15164    fn left_recursive_loop_with_caller_follow_atn(caller_symbol: i32) -> Atn {
15165        let mut atn = ParserAtnBuilder::new(2);
15166        assert_eq!(
15167            atn.add_state(AtnStateKind::RuleStart, Some(0))
15168                .expect("state")
15169                .index(),
15170            0
15171        );
15172        assert_eq!(
15173            atn.add_state(AtnStateKind::Basic, Some(0))
15174                .expect("state")
15175                .index(),
15176            1
15177        );
15178        assert_eq!(
15179            atn.add_state(AtnStateKind::Basic, Some(0))
15180                .expect("state")
15181                .index(),
15182            2
15183        );
15184        assert_eq!(
15185            atn.add_state(AtnStateKind::RuleStart, Some(1))
15186                .expect("state")
15187                .index(),
15188            3
15189        );
15190        atn.set_left_recursive_rule(3)
15191            .expect("left-recursive rule start");
15192        assert_eq!(
15193            atn.add_state(AtnStateKind::StarLoopEntry, Some(1))
15194                .expect("state")
15195                .index(),
15196            4
15197        );
15198        atn.set_precedence_rule_decision(4)
15199            .expect("precedence decision");
15200        assert_eq!(
15201            atn.add_state(AtnStateKind::Basic, Some(1))
15202                .expect("state")
15203                .index(),
15204            5
15205        );
15206        assert_eq!(
15207            atn.add_state(AtnStateKind::Basic, Some(1))
15208                .expect("state")
15209                .index(),
15210            6
15211        );
15212        assert_eq!(
15213            atn.add_state(AtnStateKind::LoopEnd, Some(1))
15214                .expect("state")
15215                .index(),
15216            7
15217        );
15218        assert_eq!(
15219            atn.add_state(AtnStateKind::RuleStop, Some(1))
15220                .expect("state")
15221                .index(),
15222            8
15223        );
15224        assert_eq!(
15225            atn.add_state(AtnStateKind::RuleStop, Some(0))
15226                .expect("state")
15227                .index(),
15228            9
15229        );
15230        atn.set_rule_to_start_state(vec![0, 3])
15231            .expect("rule start states");
15232        atn.set_rule_to_stop_state(vec![9, 8])
15233            .expect("rule stop states");
15234        atn.add_transition(
15235            1,
15236            ParserTransitionSpec::Rule {
15237                target: 3,
15238                rule_index: 1,
15239                follow_state: 2,
15240                precedence: 0,
15241            },
15242        )
15243        .expect("transition");
15244        atn.add_transition(
15245            2,
15246            ParserTransitionSpec::Atom {
15247                target: 9,
15248                label: caller_symbol,
15249            },
15250        )
15251        .expect("transition");
15252        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15253            .expect("transition");
15254        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 7 })
15255            .expect("transition");
15256        atn.add_transition(
15257            5,
15258            ParserTransitionSpec::Precedence {
15259                target: 6,
15260                precedence: 1,
15261            },
15262        )
15263        .expect("transition");
15264        atn.add_transition(
15265            6,
15266            ParserTransitionSpec::Atom {
15267                target: 4,
15268                label: 1,
15269            },
15270        )
15271        .expect("transition");
15272        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
15273            .expect("transition");
15274        finish_atn(atn)
15275    }
15276
15277    fn labeled_left_recursive_operator_atn() -> Atn {
15278        let mut atn = ParserAtnBuilder::new(4);
15279        for (state, kind) in [
15280            (0, AtnStateKind::RuleStart),
15281            (1, AtnStateKind::BlockStart),
15282            (2, AtnStateKind::StarLoopEntry),
15283            (3, AtnStateKind::StarBlockStart),
15284            (4, AtnStateKind::Basic),
15285            (5, AtnStateKind::Basic),
15286            (6, AtnStateKind::Basic),
15287            (7, AtnStateKind::StarLoopBack),
15288            (8, AtnStateKind::LoopEnd),
15289            (9, AtnStateKind::RuleStop),
15290        ] {
15291            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15292        }
15293        atn.set_left_recursive_rule(0)
15294            .expect("left-recursive rule start");
15295        atn.set_precedence_rule_decision(2)
15296            .expect("precedence decision");
15297        atn.set_loop_back_state(8, 7).expect("loop-back state");
15298        atn.set_rule_to_start_state(vec![0])
15299            .expect("rule start states");
15300        atn.set_rule_to_stop_state(vec![9])
15301            .expect("rule stop states");
15302        for state in [1, 2, 3] {
15303            atn.add_decision_state(state).expect("decision state");
15304        }
15305        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
15306            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
15307                .expect("epsilon transition");
15308        }
15309        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3), (6, 7, 1)] {
15310            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
15311                .expect("token transition");
15312        }
15313        for (target, precedence) in [(4, 2), (5, 1)] {
15314            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
15315                .expect("operator precedence");
15316        }
15317        finish_atn(atn)
15318    }
15319
15320    fn parser_inside_left_recursive_callee(symbol: i32) -> BaseParser<Source> {
15321        let mut parser = mini_parser(vec![
15322            TestToken::new(symbol).with_text("lookahead"),
15323            TestToken::eof("parser-test", 1, 1, 1),
15324        ]);
15325        parser.rule_context_stack = vec![
15326            RuleContextFrame {
15327                rule_index: 0,
15328                invoking_state: -1,
15329            },
15330            RuleContextFrame {
15331                rule_index: 1,
15332                invoking_state: 1,
15333            },
15334        ];
15335        parser
15336    }
15337
15338    fn left_recursive_loop_with_shared_gt_prefix_atn() -> Atn {
15339        // StarLoopEntry with two operator alts that share leading token 1 (`>`):
15340        //   prec 2: token 1, token 1  (shift `>>`)
15341        //   prec 1: token 1           (relational `>`)
15342        let mut atn = ParserAtnBuilder::new(1);
15343        for (state, kind, rule) in [
15344            (0, AtnStateKind::RuleStart, 0),
15345            (1, AtnStateKind::StarLoopEntry, 0),
15346            (2, AtnStateKind::Basic, 0), // ops hub
15347            (3, AtnStateKind::Basic, 0), // shift prec
15348            (4, AtnStateKind::Basic, 0), // shift first >
15349            (5, AtnStateKind::Basic, 0), // shift second >
15350            (6, AtnStateKind::Basic, 0), // rel prec
15351            (7, AtnStateKind::Basic, 0), // rel >
15352            (8, AtnStateKind::LoopEnd, 0),
15353            (9, AtnStateKind::RuleStop, 0),
15354        ] {
15355            assert_eq!(
15356                atn.add_state(kind, Some(rule)).expect("state").index(),
15357                state
15358            );
15359            if state == 0 {
15360                atn.set_left_recursive_rule(state)
15361                    .expect("left-recursive rule start");
15362            } else if state == 1 {
15363                atn.set_precedence_rule_decision(state)
15364                    .expect("precedence decision");
15365            }
15366        }
15367        atn.set_rule_to_start_state(vec![0])
15368            .expect("rule start states");
15369        atn.set_rule_to_stop_state(vec![9])
15370            .expect("rule stop states");
15371        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15372            .expect("ops");
15373        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15374            .expect("exit");
15375        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15376            .expect("to shift");
15377        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15378            .expect("to rel");
15379        atn.add_transition(
15380            3,
15381            ParserTransitionSpec::Precedence {
15382                target: 4,
15383                precedence: 2,
15384            },
15385        )
15386        .expect("shift prec");
15387        atn.add_transition(
15388            4,
15389            ParserTransitionSpec::Atom {
15390                target: 5,
15391                label: 1,
15392            },
15393        )
15394        .expect("shift first >");
15395        atn.add_transition(
15396            5,
15397            ParserTransitionSpec::Atom {
15398                target: 1,
15399                label: 1,
15400            },
15401        )
15402        .expect("shift second >");
15403        atn.add_transition(
15404            6,
15405            ParserTransitionSpec::Precedence {
15406                target: 7,
15407                precedence: 1,
15408            },
15409        )
15410        .expect("rel prec");
15411        atn.add_transition(
15412            7,
15413            ParserTransitionSpec::Atom {
15414                target: 1,
15415                label: 1,
15416            },
15417        )
15418        .expect("rel >");
15419        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15420            .expect("loop end");
15421        finish_atn(atn)
15422    }
15423
15424    fn left_recursive_loop_with_rule_wrapped_gt_prefix_atn() -> Atn {
15425        let mut atn = ParserAtnBuilder::new(2);
15426        for (state, kind, rule) in [
15427            (0, AtnStateKind::RuleStart, 0),
15428            (1, AtnStateKind::StarLoopEntry, 0),
15429            (2, AtnStateKind::Basic, 0),
15430            (3, AtnStateKind::Basic, 0),
15431            (4, AtnStateKind::Basic, 0),
15432            (5, AtnStateKind::Basic, 0),
15433            (6, AtnStateKind::Basic, 0),
15434            (7, AtnStateKind::Basic, 0),
15435            (8, AtnStateKind::LoopEnd, 0),
15436            (9, AtnStateKind::RuleStop, 0),
15437            (10, AtnStateKind::RuleStart, 1),
15438            (11, AtnStateKind::Basic, 1),
15439            (12, AtnStateKind::RuleStop, 1),
15440        ] {
15441            assert_eq!(
15442                atn.add_state(kind, Some(rule)).expect("state").index(),
15443                state
15444            );
15445            if state == 0 {
15446                atn.set_left_recursive_rule(state)
15447                    .expect("left-recursive rule start");
15448            } else if state == 1 {
15449                atn.set_precedence_rule_decision(state)
15450                    .expect("precedence decision");
15451            }
15452        }
15453        atn.set_rule_to_start_state(vec![0, 10])
15454            .expect("rule start states");
15455        atn.set_rule_to_stop_state(vec![9, 12])
15456            .expect("rule stop states");
15457        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15458            .expect("ops");
15459        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 8 })
15460            .expect("exit");
15461        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15462            .expect("to shift");
15463        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15464            .expect("to relational");
15465        atn.add_transition(
15466            3,
15467            ParserTransitionSpec::Precedence {
15468                target: 4,
15469                precedence: 2,
15470            },
15471        )
15472        .expect("shift precedence");
15473        atn.add_transition(
15474            4,
15475            ParserTransitionSpec::Rule {
15476                target: 10,
15477                rule_index: 1,
15478                follow_state: 5,
15479                precedence: 0,
15480            },
15481        )
15482        .expect("first shift token helper");
15483        atn.add_transition(
15484            5,
15485            ParserTransitionSpec::Atom {
15486                target: 1,
15487                label: 1,
15488            },
15489        )
15490        .expect("second shift token");
15491        atn.add_transition(
15492            6,
15493            ParserTransitionSpec::Precedence {
15494                target: 7,
15495                precedence: 1,
15496            },
15497        )
15498        .expect("relational precedence");
15499        atn.add_transition(
15500            7,
15501            ParserTransitionSpec::Atom {
15502                target: 1,
15503                label: 1,
15504            },
15505        )
15506        .expect("relational token");
15507        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
15508            .expect("loop end");
15509        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
15510            .expect("helper entry");
15511        atn.add_transition(
15512            11,
15513            ParserTransitionSpec::Atom {
15514                target: 12,
15515                label: 1,
15516            },
15517        )
15518        .expect("first shift token");
15519        finish_atn(atn)
15520    }
15521
15522    fn left_recursive_loop_with_predicate_and_multi_token_prefix_atn() -> Atn {
15523        let mut atn = ParserAtnBuilder::new(1);
15524        for (state, kind) in [
15525            (0, AtnStateKind::RuleStart),
15526            (1, AtnStateKind::StarLoopEntry),
15527            (2, AtnStateKind::Basic),
15528            (3, AtnStateKind::Basic),
15529            (4, AtnStateKind::Basic),
15530            (5, AtnStateKind::Basic),
15531            (6, AtnStateKind::Basic),
15532            (7, AtnStateKind::Basic),
15533            (8, AtnStateKind::Basic),
15534            (9, AtnStateKind::LoopEnd),
15535            (10, AtnStateKind::RuleStop),
15536        ] {
15537            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15538            if state == 0 {
15539                atn.set_left_recursive_rule(state)
15540                    .expect("left-recursive rule start");
15541            } else if state == 1 {
15542                atn.set_precedence_rule_decision(state)
15543                    .expect("precedence decision");
15544            }
15545        }
15546        atn.set_rule_to_start_state(vec![0])
15547            .expect("rule start states");
15548        atn.set_rule_to_stop_state(vec![10])
15549            .expect("rule stop states");
15550        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15551            .expect("ops");
15552        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 9 })
15553            .expect("exit");
15554        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
15555            .expect("to multi-token operator");
15556        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 6 })
15557            .expect("to predicate operator");
15558        atn.add_transition(
15559            3,
15560            ParserTransitionSpec::Precedence {
15561                target: 4,
15562                precedence: 2,
15563            },
15564        )
15565        .expect("multi-token precedence");
15566        atn.add_transition(
15567            4,
15568            ParserTransitionSpec::Atom {
15569                target: 5,
15570                label: 1,
15571            },
15572        )
15573        .expect("multi-token first");
15574        atn.add_transition(
15575            5,
15576            ParserTransitionSpec::Atom {
15577                target: 1,
15578                label: 1,
15579            },
15580        )
15581        .expect("multi-token second");
15582        atn.add_transition(
15583            6,
15584            ParserTransitionSpec::Precedence {
15585                target: 7,
15586                precedence: 2,
15587            },
15588        )
15589        .expect("predicate precedence");
15590        atn.add_transition(
15591            7,
15592            ParserTransitionSpec::Predicate {
15593                target: 8,
15594                rule_index: 0,
15595                pred_index: 0,
15596                context_dependent: false,
15597            },
15598        )
15599        .expect("operator predicate");
15600        atn.add_transition(
15601            8,
15602            ParserTransitionSpec::Atom {
15603                target: 1,
15604                label: 1,
15605            },
15606        )
15607        .expect("predicate single token");
15608        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15609            .expect("loop end");
15610        finish_atn(atn)
15611    }
15612
15613    fn left_recursive_loop_with_nullable_operator_prefix_atn() -> Atn {
15614        let mut atn = ParserAtnBuilder::new(2);
15615        for (state, kind, rule) in [
15616            (0, AtnStateKind::RuleStart, 0),
15617            (1, AtnStateKind::StarLoopEntry, 0),
15618            (2, AtnStateKind::Basic, 0),
15619            (3, AtnStateKind::Basic, 0),
15620            (4, AtnStateKind::Basic, 0),
15621            (5, AtnStateKind::LoopEnd, 0),
15622            (6, AtnStateKind::RuleStop, 0),
15623            (7, AtnStateKind::RuleStart, 1),
15624            (8, AtnStateKind::RuleStop, 1),
15625            (9, AtnStateKind::Basic, 1),
15626        ] {
15627            assert_eq!(
15628                atn.add_state(kind, Some(rule)).expect("state").index(),
15629                state
15630            );
15631            if state == 0 {
15632                atn.set_left_recursive_rule(state)
15633                    .expect("left-recursive rule start");
15634            } else if state == 1 {
15635                atn.set_precedence_rule_decision(state)
15636                    .expect("precedence decision");
15637            }
15638        }
15639        atn.set_rule_to_start_state(vec![0, 7])
15640            .expect("rule start states");
15641        atn.set_rule_to_stop_state(vec![6, 8])
15642            .expect("rule stop states");
15643        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15644            .expect("transition");
15645        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15646            .expect("transition");
15647        atn.add_transition(
15648            2,
15649            ParserTransitionSpec::Precedence {
15650                target: 3,
15651                precedence: 3,
15652            },
15653        )
15654        .expect("transition");
15655        atn.add_transition(
15656            3,
15657            ParserTransitionSpec::Rule {
15658                target: 7,
15659                rule_index: 1,
15660                follow_state: 4,
15661                precedence: 0,
15662            },
15663        )
15664        .expect("transition");
15665        atn.add_transition(
15666            4,
15667            ParserTransitionSpec::Atom {
15668                target: 1,
15669                label: 1,
15670            },
15671        )
15672        .expect("transition");
15673        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15674            .expect("transition");
15675        atn.add_transition(
15676            7,
15677            ParserTransitionSpec::Precedence {
15678                target: 9,
15679                precedence: 1,
15680            },
15681        )
15682        .expect("transition");
15683        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 8 })
15684            .expect("transition");
15685        finish_atn(atn)
15686    }
15687
15688    fn left_recursive_loop_with_predicate_guarded_operator_atn() -> Atn {
15689        let mut atn = ParserAtnBuilder::new(2);
15690        for (state, kind) in [
15691            (0, AtnStateKind::RuleStart),
15692            (1, AtnStateKind::StarLoopEntry),
15693            (2, AtnStateKind::Basic),
15694            (3, AtnStateKind::Basic),
15695            (4, AtnStateKind::Basic),
15696            (5, AtnStateKind::LoopEnd),
15697            (6, AtnStateKind::RuleStop),
15698        ] {
15699            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
15700            if state == 0 {
15701                atn.set_left_recursive_rule(state)
15702                    .expect("left-recursive rule start");
15703            } else if state == 1 {
15704                atn.set_precedence_rule_decision(state)
15705                    .expect("precedence decision");
15706            }
15707        }
15708        atn.set_rule_to_start_state(vec![0])
15709            .expect("rule start states");
15710        atn.set_rule_to_stop_state(vec![6])
15711            .expect("rule stop states");
15712        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
15713            .expect("transition");
15714        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
15715            .expect("transition");
15716        atn.add_transition(
15717            2,
15718            ParserTransitionSpec::Precedence {
15719                target: 3,
15720                precedence: 1,
15721            },
15722        )
15723        .expect("transition");
15724        atn.add_transition(
15725            3,
15726            ParserTransitionSpec::Predicate {
15727                target: 4,
15728                rule_index: 0,
15729                pred_index: 0,
15730                context_dependent: false,
15731            },
15732        )
15733        .expect("transition");
15734        atn.add_transition(
15735            4,
15736            ParserTransitionSpec::Atom {
15737                target: 1,
15738                label: 1,
15739            },
15740        )
15741        .expect("transition");
15742        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15743            .expect("transition");
15744        finish_atn(atn)
15745    }
15746
15747    fn left_recursive_loop_with_nullable_follow_call_atn(caller_symbol: i32) -> Atn {
15748        let mut atn = ParserAtnBuilder::new(2);
15749        for (state, kind, rule) in [
15750            (0, AtnStateKind::RuleStart, 0),
15751            (1, AtnStateKind::Basic, 0),
15752            (2, AtnStateKind::Basic, 0),
15753            (3, AtnStateKind::Basic, 0),
15754            (4, AtnStateKind::RuleStop, 0),
15755            (5, AtnStateKind::RuleStart, 1),
15756            (6, AtnStateKind::StarLoopEntry, 1),
15757            (7, AtnStateKind::Basic, 1),
15758            (8, AtnStateKind::Basic, 1),
15759            (9, AtnStateKind::LoopEnd, 1),
15760            (10, AtnStateKind::RuleStop, 1),
15761            (11, AtnStateKind::RuleStart, 2),
15762            (12, AtnStateKind::RuleStop, 2),
15763        ] {
15764            assert_eq!(
15765                atn.add_state(kind, Some(rule)).expect("state").index(),
15766                state
15767            );
15768            if state == 5 {
15769                atn.set_left_recursive_rule(state)
15770                    .expect("left-recursive rule start");
15771            } else if state == 6 {
15772                atn.set_precedence_rule_decision(state)
15773                    .expect("precedence decision");
15774            }
15775        }
15776        atn.set_rule_to_start_state(vec![0, 5, 11])
15777            .expect("rule start states");
15778        atn.set_rule_to_stop_state(vec![4, 10, 12])
15779            .expect("rule stop states");
15780        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15781            .expect("transition");
15782        atn.add_transition(
15783            1,
15784            ParserTransitionSpec::Rule {
15785                target: 5,
15786                rule_index: 1,
15787                follow_state: 2,
15788                precedence: 0,
15789            },
15790        )
15791        .expect("transition");
15792        atn.add_transition(
15793            2,
15794            ParserTransitionSpec::Rule {
15795                target: 11,
15796                rule_index: 2,
15797                follow_state: 3,
15798                precedence: 0,
15799            },
15800        )
15801        .expect("transition");
15802        atn.add_transition(
15803            3,
15804            ParserTransitionSpec::Atom {
15805                target: 4,
15806                label: caller_symbol,
15807            },
15808        )
15809        .expect("transition");
15810        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15811            .expect("transition");
15812        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 9 })
15813            .expect("transition");
15814        atn.add_transition(
15815            7,
15816            ParserTransitionSpec::Precedence {
15817                target: 8,
15818                precedence: 1,
15819            },
15820        )
15821        .expect("transition");
15822        atn.add_transition(
15823            8,
15824            ParserTransitionSpec::Atom {
15825                target: 6,
15826                label: 1,
15827            },
15828        )
15829        .expect("transition");
15830        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15831            .expect("transition");
15832        atn.add_transition(11, ParserTransitionSpec::Epsilon { target: 12 })
15833            .expect("transition");
15834        finish_atn(atn)
15835    }
15836
15837    fn left_recursive_loop_with_nullable_parent_return_atn(caller_symbol: i32) -> Atn {
15838        let mut atn = ParserAtnBuilder::new(2);
15839        for (state, kind, rule) in [
15840            (0, AtnStateKind::RuleStart, 0),
15841            (1, AtnStateKind::Basic, 0),
15842            (2, AtnStateKind::Basic, 0),
15843            (3, AtnStateKind::RuleStop, 0),
15844            (4, AtnStateKind::RuleStart, 1),
15845            (5, AtnStateKind::Basic, 1),
15846            (6, AtnStateKind::Basic, 1),
15847            (7, AtnStateKind::RuleStop, 1),
15848            (8, AtnStateKind::RuleStart, 2),
15849            (9, AtnStateKind::StarLoopEntry, 2),
15850            (10, AtnStateKind::Basic, 2),
15851            (11, AtnStateKind::Basic, 2),
15852            (12, AtnStateKind::LoopEnd, 2),
15853            (13, AtnStateKind::RuleStop, 2),
15854        ] {
15855            assert_eq!(
15856                atn.add_state(kind, Some(rule)).expect("state").index(),
15857                state
15858            );
15859            if state == 8 {
15860                atn.set_left_recursive_rule(state)
15861                    .expect("left-recursive rule start");
15862            } else if state == 9 {
15863                atn.set_precedence_rule_decision(state)
15864                    .expect("precedence decision");
15865            }
15866        }
15867        atn.set_rule_to_start_state(vec![0, 4, 8])
15868            .expect("rule start states");
15869        atn.set_rule_to_stop_state(vec![3, 7, 13])
15870            .expect("rule stop states");
15871        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15872            .expect("transition");
15873        atn.add_transition(
15874            1,
15875            ParserTransitionSpec::Rule {
15876                target: 4,
15877                rule_index: 1,
15878                follow_state: 2,
15879                precedence: 0,
15880            },
15881        )
15882        .expect("transition");
15883        atn.add_transition(
15884            2,
15885            ParserTransitionSpec::Atom {
15886                target: 3,
15887                label: caller_symbol,
15888            },
15889        )
15890        .expect("transition");
15891        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
15892            .expect("transition");
15893        atn.add_transition(
15894            5,
15895            ParserTransitionSpec::Rule {
15896                target: 8,
15897                rule_index: 2,
15898                follow_state: 6,
15899                precedence: 0,
15900            },
15901        )
15902        .expect("transition");
15903        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
15904            .expect("transition");
15905        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
15906            .expect("transition");
15907        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 12 })
15908            .expect("transition");
15909        atn.add_transition(
15910            10,
15911            ParserTransitionSpec::Precedence {
15912                target: 11,
15913                precedence: 1,
15914            },
15915        )
15916        .expect("transition");
15917        atn.add_transition(
15918            11,
15919            ParserTransitionSpec::Atom {
15920                target: 9,
15921                label: 1,
15922            },
15923        )
15924        .expect("transition");
15925        atn.add_transition(12, ParserTransitionSpec::Epsilon { target: 13 })
15926            .expect("transition");
15927        finish_atn(atn)
15928    }
15929
15930    fn left_recursive_loop_with_recursive_operand_return_atn(caller_symbol: i32) -> Atn {
15931        let mut atn = ParserAtnBuilder::new(2);
15932        for (state, kind, rule) in [
15933            (0, AtnStateKind::RuleStart, 0),
15934            (1, AtnStateKind::Basic, 0),
15935            (2, AtnStateKind::Basic, 0),
15936            (3, AtnStateKind::RuleStop, 0),
15937            (4, AtnStateKind::RuleStart, 1),
15938            (5, AtnStateKind::StarLoopEntry, 1),
15939            (6, AtnStateKind::Basic, 1),
15940            (7, AtnStateKind::Basic, 1),
15941            (8, AtnStateKind::Basic, 1),
15942            (9, AtnStateKind::Basic, 1),
15943            (10, AtnStateKind::LoopEnd, 1),
15944            (11, AtnStateKind::RuleStop, 1),
15945        ] {
15946            assert_eq!(
15947                atn.add_state(kind, Some(rule)).expect("state").index(),
15948                state
15949            );
15950            if state == 4 {
15951                atn.set_left_recursive_rule(state)
15952                    .expect("left-recursive rule start");
15953            } else if state == 5 {
15954                atn.set_precedence_rule_decision(state)
15955                    .expect("precedence decision");
15956            }
15957        }
15958        atn.set_rule_to_start_state(vec![0, 4])
15959            .expect("rule start states");
15960        atn.set_rule_to_stop_state(vec![3, 11])
15961            .expect("rule stop states");
15962        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
15963            .expect("transition");
15964        atn.add_transition(
15965            1,
15966            ParserTransitionSpec::Rule {
15967                target: 4,
15968                rule_index: 1,
15969                follow_state: 2,
15970                precedence: 0,
15971            },
15972        )
15973        .expect("transition");
15974        atn.add_transition(
15975            2,
15976            ParserTransitionSpec::Atom {
15977                target: 3,
15978                label: caller_symbol,
15979            },
15980        )
15981        .expect("transition");
15982        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
15983            .expect("transition");
15984        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 10 })
15985            .expect("transition");
15986        atn.add_transition(
15987            6,
15988            ParserTransitionSpec::Precedence {
15989                target: 7,
15990                precedence: 1,
15991            },
15992        )
15993        .expect("transition");
15994        atn.add_transition(
15995            7,
15996            ParserTransitionSpec::Atom {
15997                target: 8,
15998                label: 1,
15999            },
16000        )
16001        .expect("transition");
16002        atn.add_transition(
16003            8,
16004            ParserTransitionSpec::Rule {
16005                target: 4,
16006                rule_index: 1,
16007                follow_state: 9,
16008                precedence: 2,
16009            },
16010        )
16011        .expect("transition");
16012        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 5 })
16013            .expect("transition");
16014        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
16015            .expect("transition");
16016        finish_atn(atn)
16017    }
16018
16019    #[test]
16020    fn left_recursive_loop_defers_overlapping_caller_lookahead() {
16021        let overlapping_atn = left_recursive_loop_with_caller_follow_atn(1);
16022        let unambiguous_atn = left_recursive_loop_with_caller_follow_atn(2);
16023
16024        let mut overlapping = parser_inside_left_recursive_callee(1);
16025        assert_eq!(
16026            overlapping.left_recursive_loop_enter_prediction(&overlapping_atn, 4, 0),
16027            None
16028        );
16029
16030        let mut unambiguous_enter = parser_inside_left_recursive_callee(1);
16031        assert_eq!(
16032            unambiguous_enter.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16033            Some(true)
16034        );
16035
16036        let mut unambiguous_exit = parser_inside_left_recursive_callee(2);
16037        assert_eq!(
16038            unambiguous_exit.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16039            Some(false)
16040        );
16041
16042        assert_eq!(
16043            overlapping.left_recursive_loop_enter_prediction(&unambiguous_atn, 4, 0),
16044            Some(true),
16045            "overlap results must not leak across ATNs"
16046        );
16047    }
16048
16049    #[test]
16050    fn left_recursive_loop_enters_after_nullable_operator_prefix() {
16051        let atn = left_recursive_loop_with_nullable_operator_prefix_atn();
16052        let mut parser = mini_parser(vec![
16053            TestToken::new(1).with_text("operator"),
16054            TestToken::eof("parser-test", 1, 1, 1),
16055        ]);
16056        parser.rule_context_stack = vec![RuleContextFrame {
16057            rule_index: 0,
16058            invoking_state: -1,
16059        }];
16060
16061        assert_eq!(
16062            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16063            Some(true)
16064        );
16065        assert_eq!(
16066            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16067            Some(true),
16068            "cached operator lookahead must preserve the nullable prefix return path"
16069        );
16070        assert_eq!(
16071            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16072            Some(true),
16073            "the nullable child must use its rule-call precedence, not the caller precedence"
16074        );
16075    }
16076
16077    #[test]
16078    fn left_recursive_loop_defers_multi_token_prefix_that_shadows_lower_single_token() {
16079        // Models Java `>` (relational, prec 1, one token) vs `>>` (shift, prec 2,
16080        // two tokens). At prec 2 only shift is viable; one-token lookahead on `>`
16081        // must defer so StarLoopEntry adaptive predict can exit when the second
16082        // `>` is absent (as in `a < b > c`).
16083        let atn = left_recursive_loop_with_shared_gt_prefix_atn();
16084        let mut parser = mini_parser(vec![
16085            TestToken::new(1).with_text(">"),
16086            TestToken::new(2).with_text("id"),
16087            TestToken::eof("parser-test", 1, 1, 1),
16088        ]);
16089        parser.rule_context_stack = vec![RuleContextFrame {
16090            rule_index: 0,
16091            invoking_state: -1,
16092        }];
16093
16094        assert_eq!(
16095            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16096            Some(true),
16097            "at low precedence relational `>` is a single-token operator"
16098        );
16099        assert_eq!(
16100            parser.left_recursive_loop_enter_prediction(&atn, 1, 1),
16101            Some(true),
16102            "relational remains single-token at its own precedence"
16103        );
16104        assert_eq!(
16105            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16106            None,
16107            "at shift precedence, bare `>` must not force enter"
16108        );
16109    }
16110
16111    #[test]
16112    fn left_recursive_loop_preserves_rule_wrapped_operator_continuation() {
16113        let atn = left_recursive_loop_with_rule_wrapped_gt_prefix_atn();
16114        let mut parser = mini_parser(vec![
16115            TestToken::new(1).with_text(">"),
16116            TestToken::new(2).with_text("id"),
16117            TestToken::eof("parser-test", 1, 1, 1),
16118        ]);
16119        parser.rule_context_stack = vec![RuleContextFrame {
16120            rule_index: 0,
16121            invoking_state: -1,
16122        }];
16123
16124        assert_eq!(
16125            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16126            Some(true),
16127            "the direct relational alternative remains a one-token operator"
16128        );
16129        assert_eq!(
16130            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16131            None,
16132            "a token matched in the helper rule must return to the second shift token"
16133        );
16134    }
16135
16136    #[test]
16137    fn left_recursive_loop_preserves_predicate_and_multi_token_reachability() {
16138        let atn = left_recursive_loop_with_predicate_and_multi_token_prefix_atn();
16139        let mut parser = mini_parser(vec![
16140            TestToken::new(1).with_text(">"),
16141            TestToken::new(2).with_text("id"),
16142            TestToken::eof("parser-test", 1, 1, 1),
16143        ]);
16144        parser.rule_context_stack = vec![RuleContextFrame {
16145            rule_index: 0,
16146            invoking_state: -1,
16147        }];
16148
16149        assert_eq!(
16150            parser.left_recursive_loop_enter_prediction(&atn, 1, 2),
16151            None,
16152            "a predicate-gated single-token path must not be hidden by a multi-token path"
16153        );
16154    }
16155
16156    #[test]
16157    fn left_recursive_loop_defers_predicate_guarded_operator() {
16158        let atn = left_recursive_loop_with_predicate_guarded_operator_atn();
16159        let mut parser = mini_parser_with_hooks(
16160            vec![
16161                TestToken::new(1).with_text("operator"),
16162                TestToken::eof("parser-test", 1, 1, 1),
16163            ],
16164            RejectingPredicateHooks::default(),
16165        );
16166        parser.rule_context_stack = vec![RuleContextFrame {
16167            rule_index: 0,
16168            invoking_state: -1,
16169        }];
16170
16171        assert_eq!(
16172            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16173            None,
16174            "a false predicate must be evaluated before entering the operator alternative"
16175        );
16176        assert_eq!(
16177            parser.left_recursive_loop_enter_prediction(&atn, 1, 0),
16178            None,
16179            "cached predicate-dependent lookahead must keep deferring"
16180        );
16181    }
16182
16183    #[test]
16184    fn left_recursive_loop_defers_through_nullable_caller_rule_call() {
16185        let atn = left_recursive_loop_with_nullable_follow_call_atn(1);
16186        let mut parser = parser_inside_left_recursive_callee(1);
16187
16188        assert_eq!(
16189            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16190            None
16191        );
16192        assert_eq!(
16193            parser.left_recursive_loop_enter_prediction(&atn, 6, 0),
16194            None,
16195            "the cached overlap must preserve the nullable child return path"
16196        );
16197    }
16198
16199    #[test]
16200    fn left_recursive_loop_defers_through_nullable_parent_return() {
16201        let atn = left_recursive_loop_with_nullable_parent_return_atn(1);
16202        let mut parser = mini_parser(vec![
16203            TestToken::new(1).with_text("lookahead"),
16204            TestToken::eof("parser-test", 1, 1, 1),
16205        ]);
16206        parser.rule_context_stack = vec![
16207            RuleContextFrame {
16208                rule_index: 0,
16209                invoking_state: -1,
16210            },
16211            RuleContextFrame {
16212                rule_index: 1,
16213                invoking_state: 1,
16214            },
16215            RuleContextFrame {
16216                rule_index: 2,
16217                invoking_state: 5,
16218            },
16219        ];
16220
16221        assert_eq!(
16222            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16223            None,
16224            "a nullable caller must unwind to its parent's consuming follow path"
16225        );
16226        assert_eq!(
16227            parser.left_recursive_loop_enter_prediction(&atn, 9, 0),
16228            None,
16229            "the caller-overlap cache must not retain a false negative"
16230        );
16231    }
16232
16233    #[test]
16234    fn left_recursive_loop_defers_after_recursive_operand_returns_to_loop() {
16235        let atn = left_recursive_loop_with_recursive_operand_return_atn(1);
16236        let mut parser = mini_parser(vec![
16237            TestToken::new(1).with_text("lookahead"),
16238            TestToken::eof("parser-test", 1, 1, 1),
16239        ]);
16240        parser.rule_context_stack = vec![
16241            RuleContextFrame {
16242                rule_index: 0,
16243                invoking_state: -1,
16244            },
16245            RuleContextFrame {
16246                rule_index: 1,
16247                invoking_state: 1,
16248            },
16249            RuleContextFrame {
16250                rule_index: 1,
16251                invoking_state: 8,
16252            },
16253        ];
16254
16255        assert_eq!(
16256            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16257            None,
16258            "a recursive operand return must preserve its parent caller context"
16259        );
16260        assert_eq!(
16261            parser.left_recursive_loop_enter_prediction(&atn, 5, 0),
16262            None,
16263            "the caller-overlap cache must preserve the loop-boundary return"
16264        );
16265    }
16266
16267    fn token_then_eof_atn() -> Atn {
16268        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16269            4, 1, 2, // version, parser, max token type
16270            3, // states
16271            2, 0, // rule start
16272            1, 0, // basic
16273            7, 0, // rule stop
16274            0, // non-greedy states
16275            0, // precedence states
16276            1, // rules
16277            0, // rule 0 start
16278            0, // modes
16279            0, // sets
16280            2, // transitions
16281            0, 1, 5, 1, 0, 0, // match token 1
16282            1, 2, 5, -1, 0, 0, // match EOF
16283            0, // decisions
16284        ]))
16285        .deserialize_parser()
16286        .expect("artificial parser ATN should deserialize")
16287    }
16288
16289    fn epsilon_cycle_atn() -> Atn {
16290        let mut atn = ParserAtnBuilder::new(1);
16291        for (state_number, kind) in [
16292            (0, AtnStateKind::RuleStart),
16293            (1, AtnStateKind::Basic),
16294            (2, AtnStateKind::RuleStop),
16295        ] {
16296            assert_eq!(
16297                atn.add_state(kind, Some(0)).expect("state").index(),
16298                state_number
16299            );
16300        }
16301        atn.set_rule_to_start_state(vec![0])
16302            .expect("rule start states");
16303        atn.set_rule_to_stop_state(vec![2])
16304            .expect("rule stop states");
16305        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16306            .expect("transition");
16307        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16308            .expect("self-cycle transition");
16309        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16310            .expect("exit transition");
16311        finish_atn(atn)
16312    }
16313
16314    fn committed_non_consuming_cycle_atn() -> Atn {
16315        let mut atn = ParserAtnBuilder::new(1);
16316        for (state_number, kind) in [
16317            (0, AtnStateKind::RuleStart),
16318            (1, AtnStateKind::Basic),
16319            (2, AtnStateKind::RuleStop),
16320        ] {
16321            assert_eq!(
16322                atn.add_state(kind, Some(0)).expect("state").index(),
16323                state_number
16324            );
16325        }
16326        atn.set_rule_to_start_state(vec![0])
16327            .expect("rule start states");
16328        atn.set_rule_to_stop_state(vec![2])
16329            .expect("rule stop states");
16330        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16331            .expect("cycle entry");
16332        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 1 })
16333            .expect("self-cycle transition");
16334        finish_atn(atn)
16335    }
16336
16337    fn eof_then_action_atn() -> Atn {
16338        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16339            4, 1, 1, // version, parser, max token type
16340            3, // states
16341            2, 0, // rule start
16342            1, 0, // basic
16343            7, 0, // rule stop
16344            0, // non-greedy states
16345            0, // precedence states
16346            1, // rules
16347            0, // rule 0 start
16348            0, // modes
16349            0, // sets
16350            2, // transitions
16351            0, 1, 5, -1, 0, 0, // match EOF
16352            1, 2, 6, 0, 0, 0, // parser action
16353            0, // decisions
16354        ]))
16355        .deserialize_parser()
16356        .expect("artificial parser ATN should deserialize")
16357    }
16358
16359    fn noop_action_then_token_then_eof_atn() -> Atn {
16360        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16361            4, 1, 2, // version, parser, max token type
16362            4, // states
16363            2, 0, // rule start
16364            1, 0, // basic
16365            1, 0, // basic
16366            7, 0, // rule stop
16367            0, // non-greedy states
16368            0, // precedence states
16369            1, // rules
16370            0, // rule 0 start
16371            0, // modes
16372            0, // sets
16373            3, // transitions
16374            0, 1, 6, 0, -1, 0, // no-op parser action
16375            1, 2, 5, 1, 0, 0, // match token 1
16376            2, 3, 5, -1, 0, 0, // match EOF
16377            0, // decisions
16378        ]))
16379        .deserialize_parser()
16380        .expect("artificial no-op action ATN should deserialize")
16381    }
16382
16383    fn committed_action_then_predicate_atn() -> Atn {
16384        let mut atn = ParserAtnBuilder::new(1);
16385        for (state_number, kind) in [
16386            (0, AtnStateKind::RuleStart),
16387            (1, AtnStateKind::Basic),
16388            (2, AtnStateKind::Basic),
16389            (3, AtnStateKind::Basic),
16390            (4, AtnStateKind::RuleStop),
16391        ] {
16392            assert_eq!(
16393                atn.add_state(kind, Some(0)).expect("state").index(),
16394                state_number
16395            );
16396        }
16397        atn.set_rule_to_start_state(vec![0])
16398            .expect("rule start states");
16399        atn.set_rule_to_stop_state(vec![4])
16400            .expect("rule stop states");
16401        atn.add_transition(
16402            0,
16403            ParserTransitionSpec::Action {
16404                target: 1,
16405                rule_index: 0,
16406                action_index: None,
16407                context_dependent: false,
16408            },
16409        )
16410        .expect("action transition");
16411        atn.add_transition(
16412            1,
16413            ParserTransitionSpec::Predicate {
16414                target: 2,
16415                rule_index: 0,
16416                pred_index: 0,
16417                context_dependent: false,
16418            },
16419        )
16420        .expect("predicate transition");
16421        atn.add_transition(
16422            2,
16423            ParserTransitionSpec::Atom {
16424                target: 3,
16425                label: 1,
16426            },
16427        )
16428        .expect("token transition");
16429        atn.add_transition(
16430            3,
16431            ParserTransitionSpec::Atom {
16432                target: 4,
16433                label: TOKEN_EOF,
16434            },
16435        )
16436        .expect("EOF transition");
16437        finish_atn(atn)
16438    }
16439
16440    /// ATN for `parent : child[42] {Parent();}; child[int value] : {Child();} EOF;`.
16441    fn parameterized_child_action_eof_atn() -> Atn {
16442        let mut atn = ParserAtnBuilder::new(1);
16443        for (state_number, kind, rule_index) in [
16444            (0, AtnStateKind::RuleStart, 0),
16445            (1, AtnStateKind::Basic, 0),
16446            (2, AtnStateKind::Basic, 0),
16447            (3, AtnStateKind::RuleStop, 0),
16448            (4, AtnStateKind::RuleStart, 1),
16449            (5, AtnStateKind::Basic, 1),
16450            (6, AtnStateKind::RuleStop, 1),
16451        ] {
16452            assert_eq!(
16453                atn.add_state(kind, Some(rule_index))
16454                    .expect("state")
16455                    .index(),
16456                state_number
16457            );
16458        }
16459        atn.set_rule_to_start_state(vec![0, 4])
16460            .expect("rule start states");
16461        atn.set_rule_to_stop_state(vec![3, 6])
16462            .expect("rule stop states");
16463        atn.add_transition(
16464            0,
16465            ParserTransitionSpec::Rule {
16466                target: 4,
16467                rule_index: 1,
16468                follow_state: 1,
16469                precedence: 0,
16470            },
16471        )
16472        .expect("parameterized child call");
16473        atn.add_transition(
16474            1,
16475            ParserTransitionSpec::Action {
16476                target: 2,
16477                rule_index: 0,
16478                action_index: None,
16479                context_dependent: false,
16480            },
16481        )
16482        .expect("parent action");
16483        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16484            .expect("parent stop");
16485        atn.add_transition(
16486            4,
16487            ParserTransitionSpec::Action {
16488                target: 5,
16489                rule_index: 1,
16490                action_index: None,
16491                context_dependent: false,
16492            },
16493        )
16494        .expect("child action");
16495        atn.add_transition(
16496            5,
16497            ParserTransitionSpec::Atom {
16498                target: 6,
16499                label: TOKEN_EOF,
16500            },
16501        )
16502        .expect("child EOF");
16503        finish_atn(atn)
16504    }
16505
16506    fn action_then_nested_rule_atn() -> Atn {
16507        let mut atn = ParserAtnBuilder::new(1);
16508        for (state_number, kind, rule_index) in [
16509            (0, AtnStateKind::RuleStart, 0),
16510            (1, AtnStateKind::Basic, 0),
16511            (2, AtnStateKind::Basic, 0),
16512            (3, AtnStateKind::RuleStop, 0),
16513            (4, AtnStateKind::RuleStart, 1),
16514            (5, AtnStateKind::RuleStop, 1),
16515        ] {
16516            assert_eq!(
16517                atn.add_state(kind, Some(rule_index))
16518                    .expect("state")
16519                    .index(),
16520                state_number
16521            );
16522        }
16523        atn.set_rule_to_start_state(vec![0, 4])
16524            .expect("rule start states");
16525        atn.set_rule_to_stop_state(vec![3, 5])
16526            .expect("rule stop states");
16527        atn.add_transition(
16528            0,
16529            ParserTransitionSpec::Action {
16530                target: 1,
16531                rule_index: 0,
16532                action_index: None,
16533                context_dependent: false,
16534            },
16535        )
16536        .expect("parent action");
16537        atn.add_transition(
16538            1,
16539            ParserTransitionSpec::Rule {
16540                target: 4,
16541                rule_index: 1,
16542                follow_state: 2,
16543                precedence: 0,
16544            },
16545        )
16546        .expect("nested rule call");
16547        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
16548            .expect("parent stop");
16549        atn.add_transition(
16550            4,
16551            ParserTransitionSpec::Atom {
16552                target: 5,
16553                label: TOKEN_EOF,
16554            },
16555        )
16556        .expect("child EOF");
16557        finish_atn(atn)
16558    }
16559
16560    fn losing_alternative_action_atn() -> Atn {
16561        let mut atn = ParserAtnBuilder::new(2);
16562        for (state_number, kind) in [
16563            (0, AtnStateKind::RuleStart),
16564            (1, AtnStateKind::BlockStart),
16565            (2, AtnStateKind::Basic),
16566            (3, AtnStateKind::Basic),
16567            (4, AtnStateKind::BlockEnd),
16568            (5, AtnStateKind::RuleStop),
16569        ] {
16570            assert_eq!(
16571                atn.add_state(kind, Some(0)).expect("state").index(),
16572                state_number
16573            );
16574        }
16575        atn.set_rule_to_start_state(vec![0])
16576            .expect("rule start states");
16577        atn.set_rule_to_stop_state(vec![5])
16578            .expect("rule stop states");
16579        atn.set_end_state(1, 4).expect("block end state");
16580        atn.add_decision_state(1).expect("decision state");
16581        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16582            .expect("entry transition");
16583        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16584            .expect("first alternative");
16585        atn.add_transition(
16586            1,
16587            ParserTransitionSpec::Atom {
16588                target: 4,
16589                label: 2,
16590            },
16591        )
16592        .expect("second alternative");
16593        atn.add_transition(
16594            2,
16595            ParserTransitionSpec::Action {
16596                target: 3,
16597                rule_index: 0,
16598                action_index: None,
16599                context_dependent: false,
16600            },
16601        )
16602        .expect("losing action");
16603        atn.add_transition(
16604            3,
16605            ParserTransitionSpec::Atom {
16606                target: 4,
16607                label: 1,
16608            },
16609        )
16610        .expect("first alternative token");
16611        atn.add_transition(
16612            4,
16613            ParserTransitionSpec::Atom {
16614                target: 5,
16615                label: TOKEN_EOF,
16616            },
16617        )
16618        .expect("EOF transition");
16619        finish_atn(atn)
16620    }
16621
16622    fn committed_action_star_loop_atn() -> Atn {
16623        let mut atn = ParserAtnBuilder::new(1);
16624        for (state_number, kind) in [
16625            (0, AtnStateKind::RuleStart),
16626            (1, AtnStateKind::StarLoopEntry),
16627            (2, AtnStateKind::Basic),
16628            (3, AtnStateKind::Basic),
16629            (4, AtnStateKind::StarLoopBack),
16630            (5, AtnStateKind::LoopEnd),
16631            (6, AtnStateKind::RuleStop),
16632        ] {
16633            assert_eq!(
16634                atn.add_state(kind, Some(0)).expect("state").index(),
16635                state_number
16636            );
16637        }
16638        atn.set_rule_to_start_state(vec![0])
16639            .expect("rule start states");
16640        atn.set_rule_to_stop_state(vec![6])
16641            .expect("rule stop states");
16642        atn.add_decision_state(1).expect("decision state");
16643        atn.set_loop_back_state(5, 4).expect("loop back state");
16644        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16645            .expect("entry transition");
16646        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
16647            .expect("loop body");
16648        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
16649            .expect("loop exit");
16650        atn.add_transition(
16651            2,
16652            ParserTransitionSpec::Action {
16653                target: 3,
16654                rule_index: 0,
16655                action_index: None,
16656                context_dependent: false,
16657            },
16658        )
16659        .expect("loop action");
16660        atn.add_transition(
16661            3,
16662            ParserTransitionSpec::Atom {
16663                target: 4,
16664                label: 1,
16665            },
16666        )
16667        .expect("loop token");
16668        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
16669            .expect("loop back");
16670        atn.add_transition(
16671            5,
16672            ParserTransitionSpec::Atom {
16673                target: 6,
16674                label: TOKEN_EOF,
16675            },
16676        )
16677        .expect("EOF transition");
16678        finish_atn(atn)
16679    }
16680
16681    fn committed_action_left_recursive_atn() -> Atn {
16682        let mut atn = ParserAtnBuilder::new(4);
16683        for (state, kind) in [
16684            (0, AtnStateKind::RuleStart),
16685            (1, AtnStateKind::BlockStart),
16686            (2, AtnStateKind::StarLoopEntry),
16687            (3, AtnStateKind::StarBlockStart),
16688            (4, AtnStateKind::Basic),
16689            (5, AtnStateKind::Basic),
16690            (6, AtnStateKind::Basic),
16691            (7, AtnStateKind::StarLoopBack),
16692            (8, AtnStateKind::LoopEnd),
16693            (9, AtnStateKind::RuleStop),
16694            (10, AtnStateKind::Basic),
16695        ] {
16696            assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), state);
16697        }
16698        atn.set_left_recursive_rule(0)
16699            .expect("left-recursive rule start");
16700        atn.set_precedence_rule_decision(2)
16701            .expect("precedence decision");
16702        atn.set_loop_back_state(8, 7).expect("loop-back state");
16703        atn.set_rule_to_start_state(vec![0])
16704            .expect("rule start states");
16705        atn.set_rule_to_stop_state(vec![9])
16706            .expect("rule stop states");
16707        for state in [1, 2, 3] {
16708            atn.add_decision_state(state).expect("decision state");
16709        }
16710        for (source, target) in [(0, 1), (2, 3), (2, 8), (7, 2), (8, 9)] {
16711            atn.add_transition(source, ParserTransitionSpec::Epsilon { target })
16712                .expect("epsilon transition");
16713        }
16714        for (source, target, label) in [(1, 2, 1), (1, 2, 2), (4, 6, 4), (5, 6, 3)] {
16715            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
16716                .expect("token transition");
16717        }
16718        for (target, precedence) in [(4, 2), (5, 1)] {
16719            atn.add_transition(3, ParserTransitionSpec::Precedence { target, precedence })
16720                .expect("operator precedence");
16721        }
16722        atn.add_transition(
16723            6,
16724            ParserTransitionSpec::Action {
16725                target: 10,
16726                rule_index: 0,
16727                action_index: None,
16728                context_dependent: false,
16729            },
16730        )
16731        .expect("operator action");
16732        atn.add_transition(
16733            10,
16734            ParserTransitionSpec::Atom {
16735                target: 7,
16736                label: 1,
16737            },
16738        )
16739        .expect("right operand");
16740        finish_atn(atn)
16741    }
16742
16743    fn two_alt_decision_atn() -> Atn {
16744        let mut atn = ParserAtnBuilder::new(2);
16745        assert_eq!(
16746            atn.add_state(AtnStateKind::RuleStart, Some(0))
16747                .expect("state")
16748                .index(),
16749            0
16750        );
16751        assert_eq!(
16752            atn.add_state(AtnStateKind::BlockStart, Some(0))
16753                .expect("state")
16754                .index(),
16755            1
16756        );
16757        assert_eq!(
16758            atn.add_state(AtnStateKind::Basic, Some(0))
16759                .expect("state")
16760                .index(),
16761            2
16762        );
16763        assert_eq!(
16764            atn.add_state(AtnStateKind::Basic, Some(0))
16765                .expect("state")
16766                .index(),
16767            3
16768        );
16769        assert_eq!(
16770            atn.add_state(AtnStateKind::BlockEnd, Some(0))
16771                .expect("state")
16772                .index(),
16773            4
16774        );
16775        assert_eq!(
16776            atn.add_state(AtnStateKind::RuleStop, Some(0))
16777                .expect("state")
16778                .index(),
16779            5
16780        );
16781        atn.set_rule_to_start_state(vec![0])
16782            .expect("rule start states");
16783        atn.set_rule_to_stop_state(vec![5])
16784            .expect("rule stop states");
16785        atn.add_decision_state(1).expect("decision state");
16786        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16787            .expect("transition");
16788        atn.add_transition(
16789            1,
16790            ParserTransitionSpec::Atom {
16791                target: 2,
16792                label: 1,
16793            },
16794        )
16795        .expect("transition");
16796        atn.add_transition(
16797            1,
16798            ParserTransitionSpec::Atom {
16799                target: 3,
16800                label: 2,
16801            },
16802        )
16803        .expect("transition");
16804        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 4 })
16805            .expect("transition");
16806        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
16807            .expect("transition");
16808        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
16809            .expect("transition");
16810        finish_atn(atn)
16811    }
16812
16813    /// ATN for `start : (A)? B EOF ;` (A=1, B=2, C=3, max token type 3).
16814    /// State 1 is the nullable optional-block decision; its sync set is {A, B}.
16815    fn optional_then_b_eof_atn() -> Atn {
16816        let mut atn = ParserAtnBuilder::new(3);
16817        assert_eq!(
16818            atn.add_state(AtnStateKind::RuleStart, Some(0))
16819                .expect("state")
16820                .index(),
16821            0
16822        );
16823        assert_eq!(
16824            atn.add_state(AtnStateKind::BlockStart, Some(0))
16825                .expect("state")
16826                .index(),
16827            1
16828        );
16829        assert_eq!(
16830            atn.add_state(AtnStateKind::Basic, Some(0))
16831                .expect("state")
16832                .index(),
16833            2
16834        );
16835        assert_eq!(
16836            atn.add_state(AtnStateKind::Basic, Some(0))
16837                .expect("state")
16838                .index(),
16839            3
16840        );
16841        assert_eq!(
16842            atn.add_state(AtnStateKind::Basic, Some(0))
16843                .expect("state")
16844                .index(),
16845            4
16846        );
16847        assert_eq!(
16848            atn.add_state(AtnStateKind::RuleStop, Some(0))
16849                .expect("state")
16850                .index(),
16851            5
16852        );
16853        atn.set_rule_to_start_state(vec![0])
16854            .expect("rule start states");
16855        atn.set_rule_to_stop_state(vec![5])
16856            .expect("rule stop states");
16857        atn.add_decision_state(1).expect("decision state");
16858        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16859            .expect("transition");
16860        // Optional block: match A then fall through, or skip straight to state 3.
16861        atn.add_transition(
16862            1,
16863            ParserTransitionSpec::Atom {
16864                target: 3,
16865                label: 1,
16866            },
16867        )
16868        .expect("transition");
16869        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
16870            .expect("transition");
16871        // Match B, then EOF.
16872        atn.add_transition(
16873            3,
16874            ParserTransitionSpec::Atom {
16875                target: 4,
16876                label: 2,
16877            },
16878        )
16879        .expect("transition");
16880        atn.add_transition(
16881            4,
16882            ParserTransitionSpec::Atom {
16883                target: 5,
16884                label: TOKEN_EOF,
16885            },
16886        )
16887        .expect("transition");
16888        finish_atn(atn)
16889    }
16890
16891    #[test]
16892    fn sync_decision_deletes_only_a_single_token() {
16893        // ANTLR sync recovery deletes exactly one token, only when LA(2) is
16894        // expected. `(A)? B EOF` at the optional-block decision:
16895        //  - `C B`   -> single-token deletion: one error node for the extra `C`.
16896        //  - `C C B` -> LA(2) is `C` (not expected), so NO deletion; sync returns
16897        //               without consuming and records the expected set for the
16898        //               subsequent mismatch (the parser must not over-consume both
16899        //               `C`s and accept the input).
16900        let atn = optional_then_b_eof_atn();
16901
16902        let mut single = mini_parser(vec![
16903            TestToken::new(3).with_text("c"),
16904            TestToken::new(2).with_text("b"),
16905            TestToken::eof("parser-test", 1, 2, 2),
16906        ]);
16907        single.rule_context_stack = vec![RuleContextFrame {
16908            rule_index: 0,
16909            invoking_state: 0,
16910        }];
16911        let children = single
16912            .sync_decision(&atn, 1, true, false)
16913            .expect("single extraneous token recovers");
16914        assert_eq!(children.len(), 1);
16915        assert_eq!(single.node(children[0]).kind(), NodeKind::Error);
16916        assert_eq!(single.number_of_syntax_errors(), 1);
16917        // Exactly one token consumed (the cursor now sits on `b`).
16918        assert_eq!(single.la(1), 2);
16919
16920        let mut double = mini_parser(vec![
16921            TestToken::new(3).with_text("c"),
16922            TestToken::new(3).with_text("c"),
16923            TestToken::new(2).with_text("b"),
16924            TestToken::eof("parser-test", 1, 3, 3),
16925        ]);
16926        double.rule_context_stack = vec![RuleContextFrame {
16927            rule_index: 0,
16928            invoking_state: 0,
16929        }];
16930        let result = double.sync_decision(&atn, 1, true, false);
16931        // No single-token deletion fires (LA(2) is `c`, not expected): sync must NOT
16932        // consume either `c`. It reports the mismatch at the first `c` (so the parser
16933        // does not over-consume both and accept the input). Nothing is consumed, so
16934        // the cursor still sits on the first `c` for rule-level recovery.
16935        let error = result.expect_err("two extraneous tokens must not be deleted by sync");
16936        match error {
16937            AntlrError::ParserError { message, .. } => {
16938                assert!(message.starts_with("mismatched input"), "got: {message}");
16939            }
16940            other => panic!("expected a mismatched-input ParserError, got {other:?}"),
16941        }
16942        assert_eq!(double.la(1), 3);
16943    }
16944
16945    /// The real serialized ATN that `antlr4-rust-gen` emits for
16946    /// `grammar T; s : A* EOF; A:'a'; C:'c';` — a `*` loop whose follow set after
16947    /// the loop is `EOF`. The loop decision is state 5.
16948    fn star_loop_then_eof_atn() -> Atn {
16949        AtnDeserializer::new(&SerializedAtn::from_i32(&[
16950            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,
16951            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,
16952            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,
16953            0, 0, 1, 9, 1, 1, 0, 0, 0, 1, 5,
16954        ]))
16955        .deserialize_parser()
16956        .expect("star-loop-then-EOF ATN should deserialize")
16957    }
16958
16959    /// ATN for `entry : nested EOF; nested : A*;`.
16960    ///
16961    /// State 5 is nullable within `nested`; its caller follow is EOF.
16962    fn nested_star_rule_atn() -> Atn {
16963        let mut atn = ParserAtnBuilder::new(2);
16964        for (state_number, kind, rule_index) in [
16965            (0, AtnStateKind::RuleStart, 0),
16966            (1, AtnStateKind::Basic, 0),
16967            (2, AtnStateKind::Basic, 0),
16968            (3, AtnStateKind::RuleStop, 0),
16969            (4, AtnStateKind::RuleStart, 1),
16970            (5, AtnStateKind::StarLoopEntry, 1),
16971            (6, AtnStateKind::Basic, 1),
16972            (7, AtnStateKind::StarLoopBack, 1),
16973            (8, AtnStateKind::LoopEnd, 1),
16974            (9, AtnStateKind::RuleStop, 1),
16975        ] {
16976            assert_eq!(
16977                atn.add_state(kind, Some(rule_index))
16978                    .expect("state")
16979                    .index(),
16980                state_number
16981            );
16982        }
16983        atn.set_rule_to_start_state(vec![0, 4])
16984            .expect("rule start states");
16985        atn.set_rule_to_stop_state(vec![3, 9])
16986            .expect("rule stop states");
16987        atn.add_decision_state(5).expect("decision state");
16988        atn.set_loop_back_state(8, 7).expect("loop back state");
16989        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
16990            .expect("transition");
16991        atn.add_transition(
16992            1,
16993            ParserTransitionSpec::Rule {
16994                target: 4,
16995                rule_index: 1,
16996                follow_state: 2,
16997                precedence: 0,
16998            },
16999        )
17000        .expect("transition");
17001        atn.add_transition(
17002            2,
17003            ParserTransitionSpec::Atom {
17004                target: 3,
17005                label: TOKEN_EOF,
17006            },
17007        )
17008        .expect("transition");
17009        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
17010            .expect("transition");
17011        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
17012            .expect("transition");
17013        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 8 })
17014            .expect("transition");
17015        atn.add_transition(
17016            6,
17017            ParserTransitionSpec::Atom {
17018                target: 7,
17019                label: 1,
17020            },
17021        )
17022        .expect("transition");
17023        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 5 })
17024            .expect("transition");
17025        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17026            .expect("transition");
17027        finish_atn(atn)
17028    }
17029
17030    /// ATN for `s : a+ Y ; a : X ;`.
17031    ///
17032    /// At EOF, recovery can synthesize an empty failed `a` child. The enclosing
17033    /// `+` loop must not treat that zero-width child as a successful iteration
17034    /// and then re-enter the loop at the same token index.
17035    fn plus_loop_with_recovering_body_atn() -> Atn {
17036        let mut atn = ParserAtnBuilder::new(2);
17037        assert_eq!(
17038            atn.add_state(AtnStateKind::RuleStart, Some(0))
17039                .expect("state")
17040                .index(),
17041            0
17042        );
17043        assert_eq!(
17044            atn.add_state(AtnStateKind::PlusBlockStart, Some(0))
17045                .expect("state")
17046                .index(),
17047            1
17048        );
17049        assert_eq!(
17050            atn.add_state(AtnStateKind::Basic, Some(0))
17051                .expect("state")
17052                .index(),
17053            2
17054        );
17055        assert_eq!(
17056            atn.add_state(AtnStateKind::BlockEnd, Some(0))
17057                .expect("state")
17058                .index(),
17059            3
17060        );
17061        assert_eq!(
17062            atn.add_state(AtnStateKind::PlusLoopBack, Some(0))
17063                .expect("state")
17064                .index(),
17065            4
17066        );
17067        assert_eq!(
17068            atn.add_state(AtnStateKind::LoopEnd, Some(0))
17069                .expect("state")
17070                .index(),
17071            5
17072        );
17073        assert_eq!(
17074            atn.add_state(AtnStateKind::RuleStop, Some(0))
17075                .expect("state")
17076                .index(),
17077            6
17078        );
17079        assert_eq!(
17080            atn.add_state(AtnStateKind::RuleStart, Some(1))
17081                .expect("state")
17082                .index(),
17083            7
17084        );
17085        assert_eq!(
17086            atn.add_state(AtnStateKind::Basic, Some(1))
17087                .expect("state")
17088                .index(),
17089            8
17090        );
17091        assert_eq!(
17092            atn.add_state(AtnStateKind::RuleStop, Some(1))
17093                .expect("state")
17094                .index(),
17095            9
17096        );
17097        atn.set_rule_to_start_state(vec![0, 7])
17098            .expect("rule start states");
17099        atn.set_rule_to_stop_state(vec![6, 9])
17100            .expect("rule stop states");
17101        atn.set_end_state(1, 3).expect("block end state");
17102        atn.set_loop_back_state(5, 4).expect("loop back state");
17103        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17104            .expect("transition");
17105        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17106            .expect("transition");
17107        atn.add_transition(
17108            2,
17109            ParserTransitionSpec::Rule {
17110                target: 7,
17111                rule_index: 1,
17112                follow_state: 3,
17113                precedence: 0,
17114            },
17115        )
17116        .expect("transition");
17117        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
17118            .expect("transition");
17119        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
17120            .expect("transition");
17121        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 5 })
17122            .expect("transition");
17123        atn.add_transition(
17124            5,
17125            ParserTransitionSpec::Atom {
17126                target: 6,
17127                label: 2,
17128            },
17129        )
17130        .expect("transition");
17131        atn.add_transition(
17132            7,
17133            ParserTransitionSpec::Atom {
17134                target: 8,
17135                label: 1,
17136            },
17137        )
17138        .expect("transition");
17139        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17140            .expect("transition");
17141        finish_atn(atn)
17142    }
17143
17144    #[test]
17145    fn runtime_options_default_exits_recovering_empty_plus_iteration() {
17146        let atn = plus_loop_with_recovering_body_atn();
17147        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17148
17149        let error = parser
17150            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
17151            .expect_err("EOF recovery should report a bounded mismatch");
17152
17153        let AntlrError::ParserError { message, .. } = error else {
17154            panic!("expected ParserError, got {error:?}");
17155        };
17156        insta::assert_snapshot!(message, @"mismatched input '<EOF>' expecting {'x', 2}");
17157        assert_eq!(parser.number_of_syntax_errors(), 1);
17158        assert_eq!(parser.input.index(), 0, "EOF remains unconsumed");
17159    }
17160
17161    #[test]
17162    fn sync_decision_deletes_token_before_eof_at_loop_back() {
17163        // `s : A* EOF` on `c`: the loop decision (state 5) can recover onto EOF.
17164        // At the loop ENTRY (loop_back = false) a single unexpected token before
17165        // EOF is deleted as an error node (then the generated EOF match consumes
17166        // the real EOF) — matching ANTLR's `(s c <EOF>)` + "extraneous input".
17167        // EOF must be a valid scan-stop for this to fire.
17168        let atn = star_loop_then_eof_atn();
17169        let mut parser = mini_parser(vec![
17170            TestToken::new(2).with_text("c"),
17171            TestToken::eof("parser-test", 1, 1, 1),
17172        ]);
17173        parser.rule_context_stack = vec![RuleContextFrame {
17174            rule_index: 0,
17175            invoking_state: 0,
17176        }];
17177        let children = parser
17178            .sync_decision(&atn, 5, true, false)
17179            .expect("single token before EOF recovers");
17180        assert_eq!(children.len(), 1);
17181        assert_eq!(parser.node(children[0]).kind(), NodeKind::Error);
17182        assert_eq!(parser.number_of_syntax_errors(), 1);
17183        assert_eq!(
17184            parser.la(1),
17185            TOKEN_EOF,
17186            "EOF is left for the rule's EOF match"
17187        );
17188    }
17189
17190    #[test]
17191    fn sync_decision_does_not_delete_two_tokens_before_eof_at_loop_entry() {
17192        // `s : A* EOF` on `c c`: at the loop ENTRY (loop_back = false) ANTLR does
17193        // single-token deletion, which fails because LA(2) = `c` is not expected —
17194        // so it reports `mismatched input` and consumes nothing (ANTLR: `(s c c)`
17195        // with no EOF). The scan must NOT multi-token-consume both `c`s here.
17196        let atn = star_loop_then_eof_atn();
17197        let mut parser = mini_parser(vec![
17198            TestToken::new(2).with_text("c"),
17199            TestToken::new(2).with_text("c"),
17200            TestToken::eof("parser-test", 1, 2, 2),
17201        ]);
17202        parser.rule_context_stack = vec![RuleContextFrame {
17203            rule_index: 0,
17204            invoking_state: 0,
17205        }];
17206        let error = parser
17207            .sync_decision(&atn, 5, true, false)
17208            .expect_err("two tokens at the loop entry must not be deleted");
17209        match error {
17210            AntlrError::ParserError { message, .. } => {
17211                assert!(message.starts_with("mismatched input"), "got: {message}");
17212            }
17213            other => panic!("expected mismatched-input ParserError, got {other:?}"),
17214        }
17215        assert_eq!(
17216            parser.la(1),
17217            2,
17218            "nothing consumed; cursor still on first `c`"
17219        );
17220    }
17221
17222    #[test]
17223    fn sync_decision_consumes_until_eof_at_loop_back() {
17224        // Same `s : A* EOF` decision, but at a loop-BACK (loop_back = true, i.e.
17225        // after ≥1 `A` matched). ANTLR uses multi-token `consumeUntil(recoverSet)`
17226        // there, so two unexpected tokens before EOF are BOTH deleted and the rule
17227        // recovers (matching `(s a c c <EOF>)` for input `a c c`). Here we feed the
17228        // post-`a` state directly: `c c <EOF>` with loop_back = true.
17229        let atn = star_loop_then_eof_atn();
17230        let mut parser = mini_parser(vec![
17231            TestToken::new(2).with_text("c"),
17232            TestToken::new(2).with_text("c"),
17233            TestToken::eof("parser-test", 1, 2, 2),
17234        ]);
17235        parser.rule_context_stack = vec![RuleContextFrame {
17236            rule_index: 0,
17237            invoking_state: 0,
17238        }];
17239        let children = parser
17240            .sync_decision(&atn, 5, false, true)
17241            .expect("loop-back multi-token deletion recovers onto EOF");
17242        assert_eq!(children.len(), 2, "both `c`s deleted as error nodes");
17243        assert!(
17244            children
17245                .iter()
17246                .all(|child| parser.node(*child).kind() == NodeKind::Error)
17247        );
17248        assert_eq!(parser.number_of_syntax_errors(), 1);
17249        assert_eq!(parser.la(1), TOKEN_EOF, "EOF left for the rule's EOF match");
17250    }
17251
17252    #[test]
17253    fn sync_decision_returns_before_recovery_for_nullable_exit() {
17254        let atn = nested_star_rule_atn();
17255        for (current_context_empty, loop_back) in [(true, false), (false, true)] {
17256            let mut parser = mini_parser(vec![
17257                TestToken::new(2).with_text("c"),
17258                TestToken::new(1).with_text("a"),
17259                TestToken::eof("parser-test", 1, 2, 2),
17260            ]);
17261            parser.rule_context_stack = vec![
17262                RuleContextFrame {
17263                    rule_index: 0,
17264                    invoking_state: 0,
17265                },
17266                RuleContextFrame {
17267                    rule_index: 1,
17268                    invoking_state: 1,
17269                },
17270            ];
17271
17272            let children = parser
17273                .sync_decision(&atn, 5, current_context_empty, loop_back)
17274                .expect("nullable synchronization is a no-op");
17275
17276            assert!(children.is_empty());
17277            assert_eq!(parser.la(1), 2, "the caller must receive the current token");
17278            assert_eq!(parser.number_of_syntax_errors(), 0);
17279            assert_eq!(
17280                parser
17281                    .generated_sync_expected
17282                    .as_ref()
17283                    .expect("nullable sync preserves expected symbols")
17284                    .to_btree_set(),
17285                BTreeSet::from([TOKEN_EOF, 1])
17286            );
17287        }
17288    }
17289
17290    fn predicate_after_token_atn() -> Atn {
17291        let mut atn = ParserAtnBuilder::new(2);
17292        assert_eq!(
17293            atn.add_state(AtnStateKind::RuleStart, Some(0))
17294                .expect("state")
17295                .index(),
17296            0
17297        );
17298        assert_eq!(
17299            atn.add_state(AtnStateKind::Basic, Some(0))
17300                .expect("state")
17301                .index(),
17302            1
17303        );
17304        assert_eq!(
17305            atn.add_state(AtnStateKind::Basic, Some(0))
17306                .expect("state")
17307                .index(),
17308            2
17309        );
17310        assert_eq!(
17311            atn.add_state(AtnStateKind::Basic, Some(0))
17312                .expect("state")
17313                .index(),
17314            3
17315        );
17316        assert_eq!(
17317            atn.add_state(AtnStateKind::RuleStop, Some(0))
17318                .expect("state")
17319                .index(),
17320            4
17321        );
17322        atn.set_rule_to_start_state(vec![0])
17323            .expect("rule start states");
17324        atn.set_rule_to_stop_state(vec![4])
17325            .expect("rule stop states");
17326        atn.add_transition(
17327            0,
17328            ParserTransitionSpec::Atom {
17329                target: 1,
17330                label: 1,
17331            },
17332        )
17333        .expect("transition");
17334        atn.add_transition(
17335            1,
17336            ParserTransitionSpec::Predicate {
17337                target: 2,
17338                rule_index: 0,
17339                pred_index: 0,
17340                context_dependent: false,
17341            },
17342        )
17343        .expect("transition");
17344        atn.add_transition(
17345            2,
17346            ParserTransitionSpec::Atom {
17347                target: 3,
17348                label: 2,
17349            },
17350        )
17351        .expect("transition");
17352        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
17353            .expect("transition");
17354        finish_atn(atn)
17355    }
17356
17357    fn predicate_gated_same_lookahead_atn(pred_indexes: [usize; 2]) -> Atn {
17358        let mut atn = ParserAtnBuilder::new(1);
17359        for (state_number, kind) in [
17360            (0, AtnStateKind::RuleStart),
17361            (1, AtnStateKind::BlockStart),
17362            (2, AtnStateKind::Basic),
17363            (3, AtnStateKind::Basic),
17364            (4, AtnStateKind::Basic),
17365            (5, AtnStateKind::Basic),
17366            (6, AtnStateKind::BlockEnd),
17367            (7, AtnStateKind::RuleStop),
17368        ] {
17369            assert_eq!(
17370                atn.add_state(kind, Some(0)).expect("state").index(),
17371                state_number
17372            );
17373        }
17374        atn.set_rule_to_start_state(vec![0])
17375            .expect("rule start states");
17376        atn.set_rule_to_stop_state(vec![7])
17377            .expect("rule stop states");
17378        atn.add_decision_state(1).expect("decision state");
17379        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17380            .expect("transition");
17381        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17382            .expect("transition");
17383        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17384            .expect("transition");
17385        atn.add_transition(
17386            2,
17387            ParserTransitionSpec::Predicate {
17388                target: 4,
17389                rule_index: 0,
17390                pred_index: pred_indexes[0],
17391                context_dependent: false,
17392            },
17393        )
17394        .expect("transition");
17395        atn.add_transition(
17396            3,
17397            ParserTransitionSpec::Predicate {
17398                target: 5,
17399                rule_index: 0,
17400                pred_index: pred_indexes[1],
17401                context_dependent: false,
17402            },
17403        )
17404        .expect("transition");
17405        atn.add_transition(
17406            4,
17407            ParserTransitionSpec::Atom {
17408                target: 6,
17409                label: 1,
17410            },
17411        )
17412        .expect("transition");
17413        atn.add_transition(
17414            5,
17415            ParserTransitionSpec::Atom {
17416                target: 6,
17417                label: 1,
17418            },
17419        )
17420        .expect("transition");
17421        atn.add_transition(
17422            6,
17423            ParserTransitionSpec::Atom {
17424                target: 7,
17425                label: TOKEN_EOF,
17426            },
17427        )
17428        .expect("transition");
17429        finish_atn(atn)
17430    }
17431
17432    /// ATN for `s : A B | {false}? A C | {true}? A C;`.
17433    fn semantic_fallback_viability_atn() -> Atn {
17434        let mut atn = ParserAtnBuilder::new(3);
17435        for (state_number, kind) in [
17436            (0, AtnStateKind::RuleStart),
17437            (1, AtnStateKind::BlockStart),
17438            (2, AtnStateKind::Basic),
17439            (3, AtnStateKind::Basic),
17440            (4, AtnStateKind::Basic),
17441            (5, AtnStateKind::Basic),
17442            (6, AtnStateKind::Basic),
17443            (7, AtnStateKind::Basic),
17444            (8, AtnStateKind::Basic),
17445            (9, AtnStateKind::BlockEnd),
17446            (10, AtnStateKind::RuleStop),
17447        ] {
17448            assert_eq!(
17449                atn.add_state(kind, Some(0)).expect("state").index(),
17450                state_number
17451            );
17452        }
17453        atn.set_rule_to_start_state(vec![0])
17454            .expect("rule start states");
17455        atn.set_rule_to_stop_state(vec![10])
17456            .expect("rule stop states");
17457        atn.set_end_state(1, 9).expect("block end state");
17458        atn.add_decision_state(1).expect("decision state");
17459        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17460            .expect("entry transition");
17461        atn.add_transition(
17462            1,
17463            ParserTransitionSpec::Atom {
17464                target: 2,
17465                label: 1,
17466            },
17467        )
17468        .expect("first alternative");
17469        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17470            .expect("second alternative");
17471        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
17472            .expect("third alternative");
17473        atn.add_transition(
17474            2,
17475            ParserTransitionSpec::Atom {
17476                target: 9,
17477                label: 2,
17478            },
17479        )
17480        .expect("first alternative suffix");
17481        for (source, target, pred_index) in [(3, 4, 0), (6, 7, 1)] {
17482            atn.add_transition(
17483                source,
17484                ParserTransitionSpec::Predicate {
17485                    target,
17486                    rule_index: 0,
17487                    pred_index,
17488                    context_dependent: false,
17489                },
17490            )
17491            .expect("predicate transition");
17492        }
17493        for (source, target, label) in [(4, 5, 1), (5, 9, 3), (7, 8, 1), (8, 9, 3)] {
17494            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
17495                .expect("predicate alternative token");
17496        }
17497        atn.add_transition(
17498            9,
17499            ParserTransitionSpec::Atom {
17500                target: 10,
17501                label: TOKEN_EOF,
17502            },
17503        )
17504        .expect("EOF transition");
17505        finish_atn(atn)
17506    }
17507
17508    /// ATN for `s : gated | A; gated : {false}? A;`.
17509    fn rule_call_predicate_decision_atn() -> Atn {
17510        let mut atn = ParserAtnBuilder::new(1);
17511        for (state_number, kind, rule_index) in [
17512            (0, AtnStateKind::RuleStart, 0),
17513            (1, AtnStateKind::BlockStart, 0),
17514            (2, AtnStateKind::Basic, 0),
17515            (3, AtnStateKind::Basic, 0),
17516            (4, AtnStateKind::BlockEnd, 0),
17517            (5, AtnStateKind::RuleStop, 0),
17518            (6, AtnStateKind::RuleStart, 1),
17519            (7, AtnStateKind::Basic, 1),
17520            (8, AtnStateKind::RuleStop, 1),
17521        ] {
17522            assert_eq!(
17523                atn.add_state(kind, Some(rule_index))
17524                    .expect("state")
17525                    .index(),
17526                state_number
17527            );
17528        }
17529        atn.set_rule_to_start_state(vec![0, 6])
17530            .expect("rule start states");
17531        atn.set_rule_to_stop_state(vec![5, 8])
17532            .expect("rule stop states");
17533        atn.set_end_state(1, 4).expect("block end state");
17534        atn.add_decision_state(1).expect("decision state");
17535        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17536            .expect("entry transition");
17537        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17538            .expect("gated alternative entry");
17539        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
17540            .expect("direct alternative entry");
17541        atn.add_transition(
17542            2,
17543            ParserTransitionSpec::Rule {
17544                target: 6,
17545                rule_index: 1,
17546                follow_state: 4,
17547                precedence: 0,
17548            },
17549        )
17550        .expect("gated alternative");
17551        atn.add_transition(
17552            3,
17553            ParserTransitionSpec::Atom {
17554                target: 4,
17555                label: 1,
17556            },
17557        )
17558        .expect("direct alternative");
17559        atn.add_transition(
17560            4,
17561            ParserTransitionSpec::Atom {
17562                target: 5,
17563                label: TOKEN_EOF,
17564            },
17565        )
17566        .expect("EOF transition");
17567        atn.add_transition(
17568            6,
17569            ParserTransitionSpec::Predicate {
17570                target: 7,
17571                rule_index: 1,
17572                pred_index: 0,
17573                context_dependent: false,
17574            },
17575        )
17576        .expect("callee predicate");
17577        atn.add_transition(
17578            7,
17579            ParserTransitionSpec::Atom {
17580                target: 8,
17581                label: 1,
17582            },
17583        )
17584        .expect("callee token");
17585        finish_atn(atn)
17586    }
17587
17588    /// ATN for `s : ({true}? A)* EOF;`.
17589    fn predicate_gated_star_loop_atn() -> Atn {
17590        let mut atn = ParserAtnBuilder::new(2);
17591        for (state_number, kind) in [
17592            (0, AtnStateKind::RuleStart),
17593            (1, AtnStateKind::StarLoopEntry),
17594            (2, AtnStateKind::Basic),
17595            (3, AtnStateKind::Basic),
17596            (4, AtnStateKind::StarLoopBack),
17597            (5, AtnStateKind::LoopEnd),
17598            (6, AtnStateKind::RuleStop),
17599        ] {
17600            assert_eq!(
17601                atn.add_state(kind, Some(0)).expect("state").index(),
17602                state_number
17603            );
17604        }
17605        atn.set_rule_to_start_state(vec![0])
17606            .expect("rule start states");
17607        atn.set_rule_to_stop_state(vec![6])
17608            .expect("rule stop states");
17609        atn.add_decision_state(1).expect("decision state");
17610        atn.set_loop_back_state(5, 4).expect("loop back state");
17611        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
17612            .expect("entry transition");
17613        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
17614            .expect("loop enter");
17615        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 5 })
17616            .expect("loop exit");
17617        atn.add_transition(
17618            2,
17619            ParserTransitionSpec::Predicate {
17620                target: 3,
17621                rule_index: 0,
17622                pred_index: 0,
17623                context_dependent: false,
17624            },
17625        )
17626        .expect("loop predicate");
17627        atn.add_transition(
17628            3,
17629            ParserTransitionSpec::Atom {
17630                target: 4,
17631                label: 1,
17632            },
17633        )
17634        .expect("loop token");
17635        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 1 })
17636            .expect("loop back");
17637        atn.add_transition(
17638            5,
17639            ParserTransitionSpec::Atom {
17640                target: 6,
17641                label: TOKEN_EOF,
17642            },
17643        )
17644        .expect("EOF transition");
17645        finish_atn(atn)
17646    }
17647
17648    fn nested_nullable_context_atn() -> Atn {
17649        let mut atn = ParserAtnBuilder::new(1);
17650        for state_number in 0..=20 {
17651            let kind = match state_number {
17652                0 | 10 | 16 => AtnStateKind::RuleStart,
17653                9 | 15 | 20 => AtnStateKind::RuleStop,
17654                _ => AtnStateKind::Basic,
17655            };
17656            let rule_index = match state_number {
17657                0..=9 => 0,
17658                10..=15 => 1,
17659                _ => 2,
17660            };
17661            assert_eq!(
17662                atn.add_state(kind, Some(rule_index))
17663                    .expect("state")
17664                    .index(),
17665                state_number
17666            );
17667        }
17668        atn.set_rule_to_start_state(vec![0, 10, 16])
17669            .expect("rule start states");
17670        atn.set_rule_to_stop_state(vec![9, 15, 20])
17671            .expect("rule stop states");
17672        atn.add_transition(
17673            1,
17674            ParserTransitionSpec::Rule {
17675                target: 10,
17676                rule_index: 1,
17677                follow_state: 8,
17678                precedence: 0,
17679            },
17680        )
17681        .expect("transition");
17682        atn.add_transition(
17683            8,
17684            ParserTransitionSpec::Atom {
17685                target: 9,
17686                label: 1,
17687            },
17688        )
17689        .expect("transition");
17690        atn.add_transition(8, ParserTransitionSpec::Epsilon { target: 9 })
17691            .expect("transition");
17692        atn.add_transition(
17693            2,
17694            ParserTransitionSpec::Rule {
17695                target: 16,
17696                rule_index: 2,
17697                follow_state: 14,
17698                precedence: 0,
17699            },
17700        )
17701        .expect("transition");
17702        atn.add_transition(14, ParserTransitionSpec::Epsilon { target: 15 })
17703            .expect("transition");
17704        finish_atn(atn)
17705    }
17706
17707    fn generated_match_recovery_atn() -> Atn {
17708        let mut atn = ParserAtnBuilder::new(2);
17709        assert_eq!(
17710            atn.add_state(AtnStateKind::RuleStart, Some(0))
17711                .expect("state")
17712                .index(),
17713            0
17714        );
17715        assert_eq!(
17716            atn.add_state(AtnStateKind::Basic, Some(0))
17717                .expect("state")
17718                .index(),
17719            1
17720        );
17721        assert_eq!(
17722            atn.add_state(AtnStateKind::Basic, Some(0))
17723                .expect("state")
17724                .index(),
17725            2
17726        );
17727        assert_eq!(
17728            atn.add_state(AtnStateKind::RuleStop, Some(0))
17729                .expect("state")
17730                .index(),
17731            3
17732        );
17733        assert_eq!(
17734            atn.add_state(AtnStateKind::RuleStart, Some(1))
17735                .expect("state")
17736                .index(),
17737            4
17738        );
17739        assert_eq!(
17740            atn.add_state(AtnStateKind::RuleStop, Some(1))
17741                .expect("state")
17742                .index(),
17743            5
17744        );
17745        atn.set_rule_to_start_state(vec![0, 4])
17746            .expect("rule start states");
17747        atn.set_rule_to_stop_state(vec![3, 5])
17748            .expect("rule stop states");
17749        atn.add_transition(
17750            1,
17751            ParserTransitionSpec::Rule {
17752                target: 4,
17753                rule_index: 1,
17754                follow_state: 2,
17755                precedence: 0,
17756            },
17757        )
17758        .expect("transition");
17759        atn.add_transition(
17760            2,
17761            ParserTransitionSpec::Atom {
17762                target: 3,
17763                label: TOKEN_EOF,
17764            },
17765        )
17766        .expect("transition");
17767        finish_atn(atn)
17768    }
17769
17770    fn complement_set_atn() -> Atn {
17771        let mut atn = ParserAtnBuilder::new(1);
17772        assert_eq!(
17773            atn.add_state(AtnStateKind::RuleStart, Some(0))
17774                .expect("state")
17775                .index(),
17776            0
17777        );
17778        assert_eq!(
17779            atn.add_state(AtnStateKind::RuleStop, Some(0))
17780                .expect("state")
17781                .index(),
17782            1
17783        );
17784        atn.set_rule_to_start_state(vec![0])
17785            .expect("rule start states");
17786        atn.set_rule_to_stop_state(vec![1])
17787            .expect("rule stop states");
17788        let excluded = atn.add_interval_set([(1, 1)]).expect("excluded set");
17789        atn.add_transition(
17790            0,
17791            ParserTransitionSpec::NotSet {
17792                target: 1,
17793                set: excluded,
17794            },
17795        )
17796        .expect("transition");
17797        finish_atn(atn)
17798    }
17799
17800    /// ATN for `start : . EOF ;`: a wildcard whose follow state explicitly matches
17801    /// EOF. State 0 (`RuleStart`) -wildcard-> 2 -EOF-> 1 (`RuleStop`).
17802    fn wildcard_then_eof_atn() -> Atn {
17803        let mut atn = ParserAtnBuilder::new(1);
17804        assert_eq!(
17805            atn.add_state(AtnStateKind::RuleStart, Some(0))
17806                .expect("state")
17807                .index(),
17808            0
17809        );
17810        assert_eq!(
17811            atn.add_state(AtnStateKind::RuleStop, Some(0))
17812                .expect("state")
17813                .index(),
17814            1
17815        );
17816        assert_eq!(
17817            atn.add_state(AtnStateKind::Basic, Some(0))
17818                .expect("state")
17819                .index(),
17820            2
17821        );
17822        atn.set_rule_to_start_state(vec![0])
17823            .expect("rule start states");
17824        atn.set_rule_to_stop_state(vec![1])
17825            .expect("rule stop states");
17826        atn.add_transition(0, ParserTransitionSpec::Wildcard { target: 2 })
17827            .expect("transition");
17828        atn.add_transition(
17829            2,
17830            ParserTransitionSpec::Atom {
17831                target: 1,
17832                label: TOKEN_EOF,
17833            },
17834        )
17835        .expect("transition");
17836        finish_atn(atn)
17837    }
17838
17839    #[test]
17840    fn parser_matches_token_and_reports_mismatch() {
17841        let source = Source {
17842            tokens: vec![
17843                TestToken::new(1).with_text("x"),
17844                TestToken::eof("parser-test", 1, 1, 1),
17845            ],
17846            index: 0,
17847        };
17848        let data = RecognizerData::new(
17849            "Mini.g4",
17850            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
17851        );
17852        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
17853        let matched = parser.match_token(1).expect("token 1 should match");
17854        assert_eq!(parser.node(matched).text(), "x");
17855        assert!(parser.match_token(1).is_err());
17856    }
17857
17858    #[test]
17859    fn parser_matches_token_sets() {
17860        let mut parser = mini_parser(vec![
17861            TestToken::new(1).with_text("x"),
17862            TestToken::eof("parser-test", 1, 1, 1),
17863        ]);
17864
17865        let matched = parser
17866            .match_set(&[(1, 1), (3, 4)])
17867            .expect("token set should match");
17868        assert_eq!(parser.node(matched).text(), "x");
17869        assert!(parser.match_not_set(&[(1, 1)], 1, 4).is_err());
17870    }
17871
17872    #[test]
17873    fn generated_rule_api_tracks_state_and_precedence() {
17874        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17875
17876        let context = parser.enter_rule(7, 2);
17877        assert_eq!(context.rule_index(), 2);
17878        assert_eq!(parser.state(), 7);
17879        assert_eq!(
17880            parser.rule_context_stack,
17881            vec![RuleContextFrame {
17882                rule_index: 2,
17883                invoking_state: 7
17884            }]
17885        );
17886
17887        let recursive = parser.enter_recursion_rule(11, 3, 4);
17888        assert_eq!(recursive.rule_index(), 3);
17889        assert!(parser.precpred(4));
17890        assert!(parser.precpred(5));
17891        assert!(!parser.precpred(3));
17892
17893        let next = parser.push_new_recursion_context(13, 3);
17894        assert_eq!(next.invoking_state(), 13);
17895        parser.unroll_recursion_context();
17896        assert_eq!(parser.precedence_stack, vec![0]);
17897        assert_eq!(
17898            parser.rule_context_stack,
17899            vec![RuleContextFrame {
17900                rule_index: 2,
17901                invoking_state: 7
17902            }]
17903        );
17904
17905        parser.exit_rule();
17906        assert!(parser.rule_context_stack.is_empty());
17907    }
17908
17909    #[test]
17910    fn reset_rewinds_input_and_clears_parser_owned_parse_state() {
17911        let mut parser = mini_parser(vec![
17912            TestToken::new(1).with_text("x"),
17913            TestToken::eof("parser-test", 1, 1, 1),
17914        ]);
17915        let matched = parser.match_token(1).expect("token should match");
17916        assert_eq!(parser.node(matched).text(), "x");
17917        parser.record_generated_syntax_error();
17918        parser.set_int_member(7, 11);
17919        parser.set_build_parse_trees(false);
17920        parser.set_report_diagnostic_errors(true);
17921        parser.set_prediction_mode(PredictionMode::Sll);
17922        parser.set_bail_on_error(true);
17923        let _context = parser.enter_recursion_rule(9, 0, 4);
17924        parser.pending_invoking_states.push(5);
17925        parser.unknown_predicate_hits.push((0, 1));
17926        parser.unhandled_action_hits.push((0, 2));
17927
17928        parser.reset();
17929
17930        assert_eq!(parser.input.index(), 0);
17931        assert_eq!(parser.la(1), 1);
17932        assert_eq!(parser.state(), -1);
17933        assert_eq!(parser.number_of_syntax_errors(), 0);
17934        assert_eq!(parser.parse_tree_storage().node_count(), 0);
17935        assert!(parser.rule_context_stack.is_empty());
17936        assert!(parser.pending_invoking_states.is_empty());
17937        assert_eq!(parser.precedence_stack, [0]);
17938        assert!(parser.unknown_predicate_hits.is_empty());
17939        assert!(parser.unhandled_action_hits.is_empty());
17940        assert_eq!(parser.int_member(7), Some(11));
17941        assert!(!parser.build_parse_trees());
17942        assert!(parser.report_diagnostic_errors());
17943        assert_eq!(parser.prediction_mode(), PredictionMode::Sll);
17944        assert!(parser.bail_on_error());
17945    }
17946
17947    #[test]
17948    fn set_token_stream_replaces_input_and_resets_parser() {
17949        let mut parser = mini_parser(vec![
17950            TestToken::new(1).with_text("old"),
17951            TestToken::eof("parser-test", 1, 1, 1),
17952        ]);
17953        parser.consume();
17954        parser.record_generated_syntax_error();
17955        let replacement = CommonTokenStream::new(Source {
17956            tokens: vec![
17957                TestToken::new(2).with_text("new"),
17958                TestToken::eof("parser-test", 1, 1, 1),
17959            ],
17960            index: 0,
17961        });
17962
17963        parser.set_token_stream(replacement);
17964
17965        assert_eq!(parser.input.index(), 0);
17966        assert_eq!(parser.la(1), 2);
17967        assert_eq!(parser.input.text_all(), "new");
17968        assert_eq!(parser.number_of_syntax_errors(), 0);
17969    }
17970
17971    #[test]
17972    fn active_invocation_states_exclude_the_root_frame() {
17973        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
17974
17975        let _root = parser.enter_rule(0, 0);
17976        assert!(parser.active_invocation_states().is_empty());
17977
17978        let marker = parser.push_invoking_state(6);
17979        let _child = parser.enter_rule(2, 1);
17980        parser.discard_invoking_state(marker);
17981        assert_eq!(parser.active_invocation_states(), [6]);
17982
17983        let marker = parser.push_invoking_state(13);
17984        let _grandchild = parser.enter_rule(4, 2);
17985        parser.discard_invoking_state(marker);
17986        assert_eq!(parser.active_invocation_states(), [13, 6]);
17987
17988        parser.exit_rule();
17989        parser.exit_rule();
17990        parser.exit_rule();
17991    }
17992
17993    #[test]
17994    fn parser_predicates_support_token_adjacency() {
17995        let mut parser = mini_parser(vec![
17996            TestToken::new(1).with_text("=").with_span(0, 0),
17997            TestToken::new(1).with_text(">").with_span(1, 1),
17998            TestToken::eof("parser-test", 2, 1, 2),
17999        ]);
18000        parser.consume();
18001        parser.consume();
18002
18003        let predicates = [(0, 0, ParserPredicate::TokenPairAdjacent)];
18004
18005        assert!(parser.parser_semantic_predicate_matches(&predicates, 0, 0));
18006
18007        let mut parser = mini_parser(vec![
18008            TestToken::new(1).with_text("=").with_span(0, 0),
18009            TestToken::new(1)
18010                .with_text(" ")
18011                .with_channel(HIDDEN_CHANNEL)
18012                .with_span(1, 1),
18013            TestToken::new(1).with_text(">").with_span(2, 2),
18014            TestToken::eof("parser-test", 3, 1, 3),
18015        ]);
18016        parser.consume();
18017        parser.consume();
18018
18019        assert!(!parser.parser_semantic_predicate_matches(&predicates, 0, 0));
18020    }
18021
18022    #[test]
18023    fn parser_predicates_support_context_child_text_checks() {
18024        let mut parser = mini_parser(vec![
18025            TestToken::new(1).with_text("var"),
18026            TestToken::eof("parser-test", 1, 1, 1),
18027        ]);
18028        let mut context = ParserRuleContext::new(1, 0);
18029        let mut child_context = ParserRuleContext::new(2, 0);
18030        let terminal = parser.terminal_tree(TokenId::try_from(0).expect("test token ID"));
18031        parser.tree.add_child(&mut child_context, terminal);
18032        let child = parser.rule_node(child_context);
18033        parser.tree.add_child(&mut context, child);
18034        let predicates = [(
18035            1,
18036            0,
18037            ParserPredicate::ContextChildRuleTextNotEquals {
18038                rule_index: 2,
18039                text: "var",
18040            },
18041        )];
18042
18043        assert!(
18044            !parser.parser_semantic_predicate_matches_with_context_and_local(
18045                &predicates,
18046                1,
18047                0,
18048                &context,
18049                0,
18050            )
18051        );
18052    }
18053
18054    #[test]
18055    fn context_expected_symbols_walks_nullable_parent_contexts() {
18056        let atn = nested_nullable_context_atn();
18057        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18058        parser.rule_context_stack = vec![
18059            RuleContextFrame {
18060                rule_index: 0,
18061                invoking_state: 0,
18062            },
18063            RuleContextFrame {
18064                rule_index: 1,
18065                invoking_state: 1,
18066            },
18067            RuleContextFrame {
18068                rule_index: 2,
18069                invoking_state: 2,
18070            },
18071        ];
18072
18073        let expected = parser.context_expected_symbols(&atn);
18074
18075        assert!(expected.contains(&1));
18076        assert!(expected.contains(&TOKEN_EOF));
18077    }
18078
18079    #[test]
18080    fn prediction_context_return_states_track_rule_stack_changes() {
18081        let atn = nested_nullable_context_atn();
18082        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18083        parser.rule_context_stack = vec![
18084            RuleContextFrame {
18085                rule_index: 0,
18086                invoking_state: 0,
18087            },
18088            RuleContextFrame {
18089                rule_index: 1,
18090                invoking_state: 1,
18091            },
18092            RuleContextFrame {
18093                rule_index: 2,
18094                invoking_state: 2,
18095            },
18096        ];
18097
18098        let initial_version = parser.rule_context_version();
18099        let first: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18100        let second: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18101        assert_eq!(first, second);
18102        assert_eq!(parser.rule_context_version(), initial_version);
18103
18104        parser.exit_rule();
18105        let after_pop: Vec<_> = parser.prediction_context_return_states(&atn).collect();
18106        assert_ne!(first, after_pop);
18107        assert_ne!(parser.rule_context_version(), initial_version);
18108    }
18109
18110    #[test]
18111    fn generated_match_token_recovers_missing_token_from_context_follow() {
18112        let atn = generated_match_recovery_atn();
18113        let data = RecognizerData::new(
18114            "Mini.g4",
18115            Vocabulary::new(
18116                [None, Some("'X'"), Some("'Y'")],
18117                [None, Some("X"), Some("Y")],
18118                [None::<&str>, None, None],
18119            ),
18120        );
18121        let mut parser = BaseParser::new(
18122            CommonTokenStream::new(Source {
18123                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
18124                index: 0,
18125            }),
18126            data,
18127        );
18128        parser.rule_context_stack = vec![
18129            RuleContextFrame {
18130                rule_index: 0,
18131                invoking_state: 0,
18132            },
18133            RuleContextFrame {
18134                rule_index: 1,
18135                invoking_state: 1,
18136            },
18137        ];
18138        assert_eq!(parser.number_of_syntax_errors(), 0);
18139
18140        let node = parser
18141            .match_token_recovering(2, 5, &atn)
18142            .expect("generated match should insert missing token");
18143
18144        assert_eq!(node.children().len(), 1);
18145        assert_eq!(parser.node(node.children()[0]).text(), "<missing 'Y'>");
18146        assert_eq!(
18147            node.clone()
18148                .into_child_iter()
18149                .map(|child| parser.node(child).text())
18150                .collect::<Vec<_>>(),
18151            ["<missing 'Y'>"]
18152        );
18153        // Single-token insertion synthesizes a missing token and consumes nothing,
18154        // so no EOF terminal is consumed even though lookahead is EOF.
18155        assert!(!node.consumed_eof());
18156        assert_eq!(parser.la(1), TOKEN_EOF);
18157        assert_eq!(parser.number_of_syntax_errors(), 1);
18158        assert_eq!(
18159            parser.generated_parser_diagnostics,
18160            [ParserDiagnostic {
18161                line: 1,
18162                column: 3,
18163                message: "missing 'Y' at '<EOF>'".to_owned(),
18164                offending: parser.input.lt_id(1),
18165            }]
18166        );
18167    }
18168
18169    #[test]
18170    fn generated_match_token_counts_single_token_deletion_recovery() {
18171        let atn = generated_match_recovery_atn();
18172        let data = RecognizerData::new(
18173            "Mini.g4",
18174            Vocabulary::new(
18175                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18176                [None, Some("X"), Some("Y"), Some("Z")],
18177                [None::<&str>, None, None, None],
18178            ),
18179        );
18180        let mut parser = BaseParser::new(
18181            CommonTokenStream::new(Source {
18182                tokens: vec![
18183                    TestToken::new(3).with_text("z"),
18184                    TestToken::new(2).with_text("y"),
18185                    TestToken::eof("parser-test", 3, 1, 3),
18186                ],
18187                index: 0,
18188            }),
18189            data,
18190        );
18191
18192        let node = parser
18193            .match_token_recovering(2, 5, &atn)
18194            .expect("generated match should delete the extraneous token");
18195
18196        assert_eq!(node.children().len(), 2);
18197        assert_eq!(parser.node(node.children()[0]).kind(), NodeKind::Error);
18198        assert_eq!(parser.node(node.children()[0]).text(), "z");
18199        assert_eq!(parser.node(node.children()[1]).text(), "y");
18200        assert_eq!(
18201            node.into_child_iter()
18202                .map(|child| parser.node(child).text())
18203                .collect::<Vec<_>>(),
18204            ["z", "y"]
18205        );
18206        assert_eq!(parser.number_of_syntax_errors(), 1);
18207    }
18208
18209    #[test]
18210    fn generated_match_token_iterates_single_success_without_a_children_vec() {
18211        let atn = generated_match_recovery_atn();
18212        let data = RecognizerData::new(
18213            "Mini.g4",
18214            Vocabulary::new(
18215                [None, Some("'X'"), Some("'Y'")],
18216                [None, Some("X"), Some("Y")],
18217                [None::<&str>, None, None],
18218            ),
18219        );
18220        let mut parser = BaseParser::new(
18221            CommonTokenStream::new(Source {
18222                tokens: vec![
18223                    TestToken::new(2).with_text("y"),
18224                    TestToken::eof("parser-test", 1, 1, 1),
18225                ],
18226                index: 0,
18227            }),
18228            data,
18229        );
18230
18231        let node = parser
18232            .match_token_recovering(2, 5, &atn)
18233            .expect("generated match should consume the expected token");
18234
18235        assert_eq!(
18236            node.into_child_iter()
18237                .map(|child| parser.node(child).text())
18238                .collect::<Vec<_>>(),
18239            ["y"]
18240        );
18241        assert_eq!(parser.number_of_syntax_errors(), 0);
18242    }
18243
18244    #[test]
18245    fn generated_diagnostic_restore_rolls_back_syntax_error_count() {
18246        let atn = generated_match_recovery_atn();
18247        let data = RecognizerData::new(
18248            "Mini.g4",
18249            Vocabulary::new(
18250                [None, Some("'X'"), Some("'Y'")],
18251                [None, Some("X"), Some("Y")],
18252                [None::<&str>, None, None],
18253            ),
18254        );
18255        let mut parser = BaseParser::new(
18256            CommonTokenStream::new(Source {
18257                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
18258                index: 0,
18259            }),
18260            data,
18261        );
18262        parser.rule_context_stack = vec![
18263            RuleContextFrame {
18264                rule_index: 0,
18265                invoking_state: 0,
18266            },
18267            RuleContextFrame {
18268                rule_index: 1,
18269                invoking_state: 1,
18270            },
18271        ];
18272        let marker = parser.generated_diagnostics_checkpoint();
18273
18274        let _ = parser
18275            .match_token_recovering(2, 5, &atn)
18276            .expect("generated match should insert missing token");
18277        assert_eq!(parser.number_of_syntax_errors(), 1);
18278
18279        parser.restore_generated_diagnostics(marker);
18280
18281        assert_eq!(parser.number_of_syntax_errors(), 0);
18282        assert!(parser.generated_parser_diagnostics.is_empty());
18283    }
18284
18285    #[test]
18286    fn generated_prediction_diagnostics_use_adaptive_context() {
18287        let atn = two_alt_decision_atn();
18288        let data = RecognizerData::new(
18289            "Mini.g4",
18290            Vocabulary::new(
18291                [None, Some("'x'"), Some("'y'")],
18292                [None, Some("X"), Some("Y")],
18293                [None::<&str>, None, None],
18294            ),
18295        )
18296        .with_rule_names(["s"]);
18297        let mut parser = BaseParser::new(
18298            CommonTokenStream::new(Source {
18299                tokens: vec![
18300                    TestToken::new(1)
18301                        .with_text("x")
18302                        .with_position(1, 0)
18303                        .with_span(0, 0),
18304                    TestToken::new(2)
18305                        .with_text("y")
18306                        .with_position(1, 2)
18307                        .with_span(1, 1),
18308                    TestToken::eof("parser-test", 2, 1, 3),
18309                ],
18310                index: 0,
18311            }),
18312            data,
18313        );
18314        parser.set_report_diagnostic_errors(true);
18315
18316        parser.record_generated_prediction_diagnostic(
18317            &atn,
18318            1,
18319            &ParserAtnPrediction {
18320                alt: 1,
18321                requires_full_context: true,
18322                has_semantic_context: false,
18323                diagnostic: Some(ParserAtnPredictionDiagnostic {
18324                    kind: ParserAtnPredictionDiagnosticKind::ContextSensitivity,
18325                    start_index: 0,
18326                    sll_stop_index: 1,
18327                    ll_stop_index: 0,
18328                    conflicting_alts: vec![1, 2],
18329                    exact: false,
18330                }),
18331            },
18332        );
18333        // Ambiguities from the default LL prediction mode are non-exact, so —
18334        // matching Java's exactOnly DiagnosticErrorListener — only the
18335        // attempting-full-context line is reported. Exact-ambiguity mode
18336        // reports the ambiguity itself.
18337        parser.record_generated_prediction_diagnostic(
18338            &atn,
18339            1,
18340            &ParserAtnPrediction {
18341                alt: 1,
18342                requires_full_context: true,
18343                has_semantic_context: false,
18344                diagnostic: Some(ParserAtnPredictionDiagnostic {
18345                    kind: ParserAtnPredictionDiagnosticKind::Ambiguity,
18346                    start_index: 0,
18347                    sll_stop_index: 1,
18348                    ll_stop_index: 1,
18349                    conflicting_alts: vec![1, 2],
18350                    exact: false,
18351                }),
18352            },
18353        );
18354
18355        // The full-context/context-sensitivity diagnostic trace (order + decision + input windows)
18356        // is one snapshot rather than three ParserDiagnostic literals.
18357        insta::assert_debug_snapshot!(
18358            "generated_prediction_diagnostics_use_adaptive_context",
18359            parser.generated_parser_diagnostics
18360        );
18361    }
18362
18363    #[test]
18364    fn generated_match_not_set_recovers_empty_complement_at_eof() {
18365        let atn = complement_set_atn();
18366        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18367        parser.rule_context_stack = vec![RuleContextFrame {
18368            rule_index: 0,
18369            invoking_state: 0,
18370        }];
18371
18372        let node = parser
18373            .match_not_token_set_recovering(
18374                atn.token_set(0).expect("excluded token set"),
18375                1,
18376                1,
18377                1,
18378                &atn,
18379            )
18380            .expect("empty complement should recover at EOF");
18381
18382        assert_eq!(node.children().len(), 1);
18383        // Recovery synthesizes a missing token without consuming EOF, so the
18384        // enclosing rule must not record EOF as its stop token.
18385        assert!(!node.consumed_eof());
18386        assert_eq!(parser.la(1), TOKEN_EOF);
18387        assert_eq!(
18388            parser.generated_parser_diagnostics,
18389            [ParserDiagnostic {
18390                line: 1,
18391                column: 1,
18392                message: "missing {} at '<EOF>'".to_owned(),
18393                offending: parser.input.lt_id(1),
18394            }]
18395        );
18396    }
18397
18398    #[test]
18399    fn wildcard_recovers_via_insertion_when_follow_expects_eof_at_eof() {
18400        // `start : . EOF ;` on empty input. The wildcard is modeled as an
18401        // empty-complement not-set; at EOF the follow state (the explicit EOF
18402        // match) expects EOF, so even in the start rule recovery must perform
18403        // single-token insertion (`<missing ...>`) rather than aborting — matching
18404        // ANTLR's `(start <missing ...> <EOF>)` / "missing ... at '<EOF>'".
18405        let atn = wildcard_then_eof_atn();
18406        let data = RecognizerData::new(
18407            "Mini.g4",
18408            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
18409        );
18410        let mut parser = BaseParser::new(
18411            CommonTokenStream::new(Source {
18412                tokens: vec![TestToken::eof("parser-test", 1, 1, 1)],
18413                index: 0,
18414            }),
18415            data,
18416        );
18417        parser.rule_context_stack = vec![RuleContextFrame {
18418            rule_index: 0,
18419            invoking_state: 0,
18420        }];
18421
18422        let node = parser
18423            .match_not_set_recovering(&[], 1, atn.max_token_type(), 2, &atn)
18424            .expect("wildcard at EOF should recover by insertion when follow expects EOF");
18425
18426        // A single `<missing ...>` error node is inserted; EOF is not consumed.
18427        assert_eq!(node.children().len(), 1);
18428        assert!(!node.consumed_eof());
18429        assert!(
18430            parser
18431                .node(node.children()[0])
18432                .text()
18433                .starts_with("<missing")
18434        );
18435        assert_eq!(parser.la(1), TOKEN_EOF);
18436        assert_eq!(
18437            parser.generated_parser_diagnostics,
18438            [ParserDiagnostic {
18439                line: 1,
18440                column: 1,
18441                message: "missing 'x' at '<EOF>'".to_owned(),
18442                offending: parser.input.lt_id(1),
18443            }]
18444        );
18445    }
18446
18447    #[test]
18448    fn generated_rule_recovery_consumes_to_parent_follow() {
18449        let atn = generated_match_recovery_atn();
18450        let data = RecognizerData::new(
18451            "Mini.g4",
18452            Vocabulary::new(
18453                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
18454                [None, Some("X"), Some("Y"), Some("Z")],
18455                [None::<&str>, None, None, None],
18456            ),
18457        );
18458        let mut parser = BaseParser::new(
18459            CommonTokenStream::new(Source {
18460                tokens: vec![
18461                    TestToken::new(3).with_text("z"),
18462                    TestToken::eof("parser-test", 1, 1, 1),
18463                ],
18464                index: 0,
18465            }),
18466            data,
18467        );
18468        let _parent = parser.enter_rule(0, 0);
18469        let marker = parser.push_invoking_state(1);
18470        let mut child = parser.enter_rule(4, 1);
18471        parser.discard_invoking_state(marker);
18472
18473        // The anchor recorded where the error was built must survive into the
18474        // dispatched diagnostic even though recovery consumes past it below.
18475        let offending = parser.input.lt_id(1);
18476        assert!(offending.is_some(), "the 'z' token should be buffered");
18477        parser.recover_generated_rule(
18478            &mut child,
18479            &atn,
18480            AntlrError::ParserError {
18481                line: 1,
18482                column: 0,
18483                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18484                offending,
18485            },
18486        );
18487        let tree = parser.finish_rule(child, false);
18488
18489        assert_eq!(parser.la(1), TOKEN_EOF);
18490        assert_eq!(
18491            parser.node(tree).to_string_tree_with_names(&["s", "a"]),
18492            "(a z)"
18493        );
18494        assert_eq!(parser.number_of_syntax_errors(), 1);
18495        assert_eq!(
18496            parser.generated_parser_diagnostics,
18497            [ParserDiagnostic {
18498                line: 1,
18499                column: 0,
18500                message: "mismatched input 'z' expecting {'X', 'Y'}".to_owned(),
18501                offending,
18502            }]
18503        );
18504        parser.exit_rule();
18505    }
18506
18507    #[test]
18508    fn generated_rule_recovery_forces_progress_after_repeated_error_state() {
18509        let atn = nested_nullable_context_atn();
18510        let mut parser = mini_parser(vec![
18511            TestToken::new(1).with_text("x"),
18512            TestToken::eof("parser-test", 1, 1, 1),
18513        ]);
18514        parser.rule_context_stack = vec![
18515            RuleContextFrame {
18516                rule_index: 0,
18517                invoking_state: 0,
18518            },
18519            RuleContextFrame {
18520                rule_index: 1,
18521                invoking_state: 1,
18522            },
18523            RuleContextFrame {
18524                rule_index: 2,
18525                invoking_state: 2,
18526            },
18527        ];
18528        parser.set_state(20);
18529        let mut context = ParserRuleContext::new(2, 2);
18530
18531        parser.recover_generated_rule(
18532            &mut context,
18533            &atn,
18534            AntlrError::NoViableAlternative {
18535                input: "'x'".to_owned(),
18536            },
18537        );
18538        assert_eq!(parser.input.index(), 0);
18539
18540        parser.set_state(21);
18541        parser.recover_generated_rule(
18542            &mut context,
18543            &atn,
18544            AntlrError::NoViableAlternative {
18545                input: "'x'".to_owned(),
18546            },
18547        );
18548        assert_eq!(parser.input.index(), 0);
18549        assert_eq!(
18550            parser.generated_recovery_error_states,
18551            BTreeSet::from([20, 21])
18552        );
18553
18554        parser.set_state(20);
18555        parser.recover_generated_rule(
18556            &mut context,
18557            &atn,
18558            AntlrError::NoViableAlternative {
18559                input: "'x'".to_owned(),
18560            },
18561        );
18562
18563        assert_eq!(parser.input.index(), 1);
18564        assert_eq!(parser.la(1), TOKEN_EOF);
18565        assert!(context.has_matched_child());
18566        assert_eq!(parser.generated_recovery_error_states, BTreeSet::from([20]));
18567
18568        parser.match_eof().expect("EOF should match");
18569        assert_eq!(parser.generated_recovery_error_index, None);
18570        assert!(parser.generated_recovery_error_states.is_empty());
18571    }
18572
18573    #[test]
18574    fn greedy_ll1_alt_handles_nullable_loop_exit() {
18575        let mut body_symbols = TokenBitSet::default();
18576        body_symbols.insert(1);
18577        let entry = DecisionLookahead {
18578            transitions: vec![
18579                TransitionLookSet {
18580                    symbols: body_symbols,
18581                    nullable: false,
18582                },
18583                TransitionLookSet {
18584                    symbols: TokenBitSet::default(),
18585                    nullable: true,
18586                },
18587            ],
18588        };
18589
18590        assert_eq!(ll1_unique_alt(&entry, 2), None);
18591        assert_eq!(ll1_greedy_alt(&entry, 2, false), Some(1));
18592        assert_eq!(ll1_greedy_alt(&entry, 1, false), None);
18593        assert_eq!(ll1_greedy_alt(&entry, 1, true), None);
18594    }
18595
18596    #[test]
18597    fn ordinary_repetition_builds_tree_in_input_order() {
18598        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18599            let mut parser = mini_parser(repeated_x_tokens(3));
18600            let tree = parser
18601                .parse_atn_rule(&atn, 0)
18602                .expect("ordinary repetition should parse");
18603
18604            let root = parser
18605                .node(tree)
18606                .as_rule()
18607                .expect("entry result should be a rule");
18608            let body_rules = root.child_rules(1).collect::<Vec<_>>();
18609            assert_eq!(root.text(), "xxx<EOF>");
18610            assert_eq!(body_rules.len(), 3);
18611            assert_eq!(
18612                body_rules
18613                    .iter()
18614                    .map(|rule| rule.start_id().expect("body start").index())
18615                    .collect::<Vec<_>>(),
18616                [0, 1, 2]
18617            );
18618            assert_eq!(
18619                body_rules
18620                    .iter()
18621                    .map(|rule| rule.stop_id().expect("body stop").index())
18622                    .collect::<Vec<_>>(),
18623                [0, 1, 2]
18624            );
18625            assert_eq!(parser.number_of_syntax_errors(), 0);
18626        }
18627    }
18628
18629    #[test]
18630    fn deeply_nested_deferred_rules_materialize_on_small_stack() {
18631        const DEPTH: usize = 20_000;
18632
18633        std::thread::Builder::new()
18634            .name("deferred-rule-materialization".to_owned())
18635            .stack_size(256 * 1024)
18636            .spawn(|| {
18637                let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
18638                let mut root = FastDeferredNodeId::EMPTY;
18639                for depth in 0..DEPTH {
18640                    root = parser
18641                        .recognition_arena
18642                        .deferred_rule_node(FastDeferredRule {
18643                            rule_index: u32::try_from(depth).expect("depth fits in u32"),
18644                            invoking_state: i32::try_from(depth).expect("depth fits in i32"),
18645                            start_index: 0,
18646                            stop_index: None,
18647                            deferred_children: root,
18648                            children: NodeSeqId::EMPTY,
18649                        });
18650                }
18651
18652                let (mut children, alt_number) =
18653                    parser.materialize_fast_deferred_nodes(root, NodeSeqId::EMPTY);
18654                assert_eq!(alt_number, 0);
18655                for expected_rule in (0..DEPTH).rev() {
18656                    let mut nodes = parser.recognition_arena.iter(children);
18657                    let node = nodes.next().expect("nested rule node");
18658                    assert!(nodes.next().is_none(), "each rule has one child");
18659                    let ArenaRecognizedNode::Rule {
18660                        rule_index,
18661                        children: nested,
18662                        ..
18663                    } = parser.recognition_arena.node(node)
18664                    else {
18665                        panic!("expected nested rule");
18666                    };
18667                    assert_eq!(rule_index as usize, expected_rule);
18668                    children = nested;
18669                }
18670                assert!(children.is_empty());
18671            })
18672            .expect("small-stack thread should start")
18673            .join()
18674            .expect("deferred rules should materialize without recursion");
18675    }
18676
18677    #[test]
18678    fn deferred_alternatives_preserve_left_recursive_contexts() {
18679        let mut parser = mini_parser(vec![
18680            TestToken::new(1).with_text("1"),
18681            TestToken::new(2).with_text("+"),
18682            TestToken::new(1).with_text("2"),
18683            TestToken::eof("parser-test", 3, 1, 3),
18684        ]);
18685        let base = parser.arena_token_node(0, false);
18686        let operator = parser.arena_token_node(1, false);
18687        let right = parser.arena_token_node(2, false);
18688
18689        let base = parser.recognition_arena.prepend(NodeSeqId::EMPTY, base);
18690        let base = parser.recognition_arena.deferred_fragment(base);
18691        let operator = parser.recognition_arena.prepend(NodeSeqId::EMPTY, operator);
18692        let operator = parser.recognition_arena.deferred_fragment(operator);
18693        let right = parser.recognition_arena.prepend(NodeSeqId::EMPTY, right);
18694        let right = parser.recognition_arena.deferred_fragment(right);
18695        let base_alt = parser.recognition_arena.deferred_alternative(1);
18696        let boundary = parser.recognition_arena.deferred_left_recursive_boundary(0);
18697        let operator_alt = parser.recognition_arena.deferred_alternative(6);
18698
18699        let mut deferred = FastDeferredNodeId::EMPTY;
18700        for fragment in [base_alt, base, boundary, operator_alt, operator, right] {
18701            deferred = parser
18702                .recognition_arena
18703                .concat_deferred_nodes(deferred, fragment);
18704        }
18705        let (nodes, root_alt_number) =
18706            parser.materialize_fast_deferred_nodes(deferred, NodeSeqId::EMPTY);
18707        let nodes = parser
18708            .recognition_arena
18709            .fold_left_recursive_boundaries(nodes);
18710
18711        let mut root = ParserRuleContext::new(0, -1);
18712        root.set_context_alt_number(root_alt_number);
18713        let mut cursor = nodes;
18714        while let Some(link) = parser.recognition_arena.link(cursor) {
18715            let child = parser
18716                .arena_recognized_node_tree(link.head, false, true)
18717                .expect("materialized child should become a public tree");
18718            parser.tree.add_child(&mut root, child);
18719            cursor = link.tail;
18720        }
18721        let tree = parser.rule_node(root);
18722        let contexts = parser
18723            .node(tree)
18724            .descendants()
18725            .filter_map(Node::as_rule)
18726            .map(|rule| {
18727                (
18728                    rule.rule_index(),
18729                    rule.alt_number(),
18730                    rule.context_alt_number(),
18731                    rule.text(),
18732                )
18733            })
18734            .collect::<Vec<_>>();
18735
18736        insta::assert_debug_snapshot!(
18737            "deferred_alternatives_preserve_left_recursive_contexts",
18738            contexts
18739        );
18740    }
18741
18742    #[test]
18743    fn fast_recognizer_preserves_labeled_left_recursive_operator_context() {
18744        let atn = labeled_left_recursive_operator_atn();
18745        let mut parser = mini_parser(vec![
18746            TestToken::new(1).with_text("a"),
18747            TestToken::new(3).with_text("+"),
18748            TestToken::new(1).with_text("b"),
18749            TestToken::eof("parser-test", 3, 1, 3),
18750        ]);
18751
18752        let (tree, _) = parser
18753            .parse_atn_rule_with_runtime_options(
18754                &atn,
18755                0,
18756                ParserRuntimeOptions {
18757                    track_context_alt_numbers: true,
18758                    ..ParserRuntimeOptions::default()
18759                },
18760            )
18761            .expect("labeled left-recursive addition should parse");
18762        let contexts = parser
18763            .node(tree)
18764            .descendants()
18765            .filter_map(Node::as_rule)
18766            .map(|rule| {
18767                let operator = rule
18768                    .children()
18769                    .next()
18770                    .and_then(Node::as_rule)
18771                    .is_some_and(|child| child.rule_index() == rule.rule_index());
18772                (operator, rule.context_alt_number(), rule.text())
18773            })
18774            .collect::<Vec<_>>();
18775
18776        insta::assert_debug_snapshot!(
18777            "fast_recognizer_preserves_labeled_left_recursive_operator_context",
18778            contexts
18779        );
18780        assert!(!parser.recognition_arena.deferred_nodes.is_empty());
18781        assert_eq!(parser.number_of_syntax_errors(), 0);
18782    }
18783
18784    #[test]
18785    fn deeply_nested_rule_calls_grow_the_stack() {
18786        const DEPTH: usize = 4_096;
18787        const STACK_SIZE: usize = 256 * 1024;
18788        let atn = nested_rule_chain_atn(DEPTH);
18789        std::thread::Builder::new()
18790            .name("nested-adaptive-set-rules".to_owned())
18791            .stack_size(STACK_SIZE)
18792            .spawn(move || {
18793                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
18794                parser.set_build_parse_trees(false);
18795                // This test isolates recognizer depth from the separately
18796                // cached FIRST-set metadata walk.
18797                parser.fast_first_set_prefilter = false;
18798                parser
18799                    .parse_atn_rule(&atn, 0)
18800                    .expect("nested rule chain should grow the native stack");
18801                assert_eq!(parser.input.index(), 1);
18802            })
18803            .expect("small-stack thread should start")
18804            .join()
18805            .expect("nested rule chain should not overflow its stack");
18806    }
18807
18808    #[test]
18809    fn deeply_nested_branching_rules_grow_the_stack() {
18810        const DEPTH: usize = 4_096;
18811        const STACK_SIZE: usize = 256 * 1024;
18812        let atn = nested_rule_graph_atn(DEPTH, true, false);
18813        std::thread::Builder::new()
18814            .name("nested-branching-rules".to_owned())
18815            .stack_size(STACK_SIZE)
18816            .spawn(move || {
18817                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
18818                parser.set_build_parse_trees(false);
18819                parser
18820                    .parse_atn_rule(&atn, 0)
18821                    .expect("branching rule chain should grow the native stack");
18822                assert_eq!(parser.input.index(), 1);
18823            })
18824            .expect("small-stack thread should start")
18825            .join()
18826            .expect("branching rule chain should not overflow its stack");
18827    }
18828
18829    #[test]
18830    fn deeply_nested_rule_follows_grow_the_stack() {
18831        const DEPTH: usize = 4_096;
18832        const STACK_SIZE: usize = 256 * 1024;
18833        let atn = nested_rule_graph_atn(DEPTH, false, true);
18834        std::thread::Builder::new()
18835            .name("nested-rule-follows".to_owned())
18836            .stack_size(STACK_SIZE)
18837            .spawn(move || {
18838                let mut parser = mini_parser(repeated_x_tokens(DEPTH));
18839                parser.set_build_parse_trees(false);
18840                parser.fast_first_set_prefilter = false;
18841                parser
18842                    .parse_atn_rule(&atn, 0)
18843                    .expect("rule follow chain should grow the native stack");
18844                assert_eq!(parser.input.index(), DEPTH);
18845            })
18846            .expect("small-stack thread should start")
18847            .join()
18848            .expect("nested rule follow chain should not overflow its stack");
18849    }
18850
18851    #[test]
18852    fn deeply_nested_recovery_grows_the_stack() {
18853        const DEPTH: usize = 4_096;
18854        const STACK_SIZE: usize = 256 * 1024;
18855        let atn = nested_rule_chain_atn(DEPTH);
18856        std::thread::Builder::new()
18857            .name("nested-rule-recovery".to_owned())
18858            .stack_size(STACK_SIZE)
18859            .spawn(move || {
18860                let mut parser = mini_parser(vec![
18861                    TestToken::new(2).with_text("z"),
18862                    TestToken::new(1).with_text("x"),
18863                    TestToken::eof("parser-test", 2, 1, 2),
18864                ]);
18865                parser.set_build_parse_trees(false);
18866                parser.fast_first_set_prefilter = false;
18867                parser
18868                    .parse_atn_rule(&atn, 0)
18869                    .expect("nested recovery should grow the native stack");
18870                assert_eq!(parser.input.index(), 2);
18871                assert_eq!(parser.number_of_syntax_errors(), 1);
18872            })
18873            .expect("small-stack thread should start")
18874            .join()
18875            .expect("nested rule recovery should not overflow its stack");
18876    }
18877
18878    #[test]
18879    fn ambiguous_ordinary_repetition_merges_equivalent_coordinates() {
18880        const REPETITIONS: usize = 64;
18881
18882        let atn = ambiguous_ordinary_star_loop_atn();
18883        let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18884        let tree = parser
18885            .parse_atn_rule(&atn, 0)
18886            .expect("ambiguous ordinary repetition should parse");
18887
18888        let root = parser
18889            .node(tree)
18890            .as_rule()
18891            .expect("entry result should be a rule");
18892        assert_eq!(root.text(), format!("{}<EOF>", "x".repeat(REPETITIONS)));
18893        assert_eq!(parser.input.index(), REPETITIONS);
18894        assert!(
18895            parser.recognition_arena.deferred_nodes.len() <= REPETITIONS * 8,
18896            "equivalent segmentations should keep deferred storage linear"
18897        );
18898        assert_eq!(parser.number_of_syntax_errors(), 0);
18899    }
18900
18901    #[test]
18902    fn long_ordinary_repetition_does_not_consume_native_stack() {
18903        const REPETITIONS: usize = 20_000;
18904
18905        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18906            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18907            parser.set_build_parse_trees(false);
18908            parser
18909                .parse_atn_rule(&atn, 0)
18910                .expect("long ordinary repetition should parse");
18911
18912            assert_eq!(parser.input.index(), REPETITIONS);
18913            assert_eq!(parser.number_of_syntax_errors(), 0);
18914        }
18915    }
18916
18917    #[test]
18918    fn long_rule_repetition_materializes_tree_with_linear_arena_growth() {
18919        const REPETITIONS: usize = 2_000;
18920        let expected_text = format!("{}<EOF>", "x".repeat(REPETITIONS));
18921
18922        for atn in [ordinary_star_loop_atn(), ordinary_plus_loop_atn()] {
18923            let mut parser = mini_parser(repeated_x_tokens(REPETITIONS));
18924            let tree = parser
18925                .parse_atn_rule(&atn, 0)
18926                .expect("long rule repetition should parse");
18927
18928            let root = parser
18929                .node(tree)
18930                .as_rule()
18931                .expect("entry result should be a rule");
18932            assert_eq!(root.text(), expected_text);
18933            assert_eq!(root.child_rules(1).count(), REPETITIONS);
18934            let first_body = root.child_rules(1).next().expect("first body rule");
18935            let last_body = root.child_rules(1).next_back().expect("last body rule");
18936            assert_eq!(first_body.start_id().expect("first body start").index(), 0);
18937            assert_eq!(
18938                last_body.stop_id().expect("last body stop").index(),
18939                REPETITIONS - 1
18940            );
18941
18942            let stats = parser.recognition_arena_stats();
18943            assert_eq!(
18944                (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
18945                (REPETITIONS, REPETITIONS, 0)
18946            );
18947            assert_eq!(
18948                (stats.total_links, stats.live_links, stats.dead_links),
18949                (REPETITIONS, REPETITIONS, 0)
18950            );
18951            assert_eq!(parser.recognition_arena.deferred_rules.len(), REPETITIONS);
18952            assert_eq!(
18953                parser.recognition_arena.deferred_nodes.len(),
18954                REPETITIONS * 2 - 1
18955            );
18956            assert_eq!(parser.number_of_syntax_errors(), 0);
18957        }
18958    }
18959
18960    #[test]
18961    fn clean_memo_probe_selects_sparse_promote_and_reprobe_modes() {
18962        let key = |state_number| FastRecognizeKey {
18963            state_number,
18964            stop_state: 10,
18965            index: state_number,
18966            rule_start_index: 0,
18967            decision_start_index: None,
18968            precedence: 0,
18969            recovery_symbols_id: 0,
18970            recovery_state: None,
18971        };
18972
18973        let mut sparse = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18974        for state_number in 0..(CLEAN_MEMO_PROBE_LIMIT - 1) {
18975            assert!(sparse.clean_memo_enabled_for_key(&key(state_number)));
18976        }
18977        assert!(!sparse.clean_memo_enabled_for_key(&key(CLEAN_MEMO_PROBE_LIMIT)));
18978        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Sparse);
18979
18980        let mut promote = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
18981        let repeated = key(1);
18982        for _ in 0..=CLEAN_MEMO_REPEAT_LIMIT {
18983            assert!(promote.clean_memo_enabled_for_key(&repeated));
18984        }
18985        assert_eq!(promote.clean_memo_mode, CleanMemoMode::Promote);
18986
18987        for _ in 1..CLEAN_MEMO_REPROBE_INTERVAL {
18988            assert!(!sparse.clean_memo_enabled_for_key(&repeated));
18989        }
18990        assert!(sparse.clean_memo_enabled_for_key(&repeated));
18991        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Probe);
18992        for _ in 0..CLEAN_MEMO_REPEAT_LIMIT {
18993            assert!(sparse.clean_memo_enabled_for_key(&repeated));
18994        }
18995        assert_eq!(sparse.clean_memo_mode, CleanMemoMode::Promote);
18996    }
18997
18998    #[test]
18999    fn fast_recognize_memo_capacity_scales_from_small_floor_to_bounded_maximum() {
19000        assert_eq!(
19001            fast_recognize_memo_capacity(0),
19002            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
19003        );
19004        assert_eq!(
19005            fast_recognize_memo_capacity(FAST_RECOGNIZE_MIN_MEMO_CAPACITY / 8),
19006            FAST_RECOGNIZE_MIN_MEMO_CAPACITY
19007        );
19008        assert_eq!(fast_recognize_memo_capacity(1_000), 8_000);
19009        assert_eq!(
19010            fast_recognize_memo_capacity(usize::MAX),
19011            FAST_RECOGNIZE_MAX_MEMO_CAPACITY
19012        );
19013    }
19014
19015    #[test]
19016    fn fast_recognize_scratch_reuses_small_tables_and_releases_oversized_memo() {
19017        let mut scratch = FastRecognizeTopScratch::default();
19018        scratch.prepare(FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
19019        let retained_capacity = scratch.memo.capacity();
19020        assert!(retained_capacity >= FAST_RECOGNIZE_MIN_MEMO_CAPACITY);
19021        assert!(retained_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19022
19023        let larger_capacity = retained_capacity + 1;
19024        scratch.prepare(larger_capacity);
19025        let grown_capacity = scratch.memo.capacity();
19026        assert!(grown_capacity >= larger_capacity);
19027        assert!(grown_capacity <= FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19028
19029        scratch.memo.insert(
19030            FastRecognizeKey {
19031                state_number: 0,
19032                stop_state: 0,
19033                index: 0,
19034                rule_start_index: 0,
19035                decision_start_index: None,
19036                precedence: 0,
19037                recovery_symbols_id: 0,
19038                recovery_state: None,
19039            },
19040            Rc::from([FastRecognizeOutcome {
19041                index: 0,
19042                consumed_eof: false,
19043                diagnostics: DiagnosticSeqId::EMPTY,
19044                deferred_nodes: FastDeferredNodeId::EMPTY,
19045                nodes: NodeSeqId::EMPTY,
19046            }]),
19047        );
19048        scratch.release_oversized_memo();
19049        assert!(scratch.memo.is_empty());
19050        assert_eq!(scratch.memo.capacity(), grown_capacity);
19051
19052        scratch
19053            .memo
19054            .reserve(FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY * 2);
19055        assert!(scratch.memo.capacity() > FAST_RECOGNIZE_MAX_RETAINED_MEMO_CAPACITY);
19056
19057        scratch.release_oversized_memo();
19058        assert!(scratch.memo.is_empty());
19059        assert_eq!(scratch.memo.capacity(), 0);
19060    }
19061
19062    #[test]
19063    fn clean_empty_multi_alt_outcomes_are_memoized() {
19064        let mut atn = ParserAtnBuilder::new(2);
19065        assert_eq!(
19066            atn.add_state(AtnStateKind::RuleStart, Some(0))
19067                .expect("state")
19068                .index(),
19069            0
19070        );
19071        assert_eq!(
19072            atn.add_state(AtnStateKind::BlockStart, Some(0))
19073                .expect("state")
19074                .index(),
19075            1
19076        );
19077        assert_eq!(
19078            atn.add_state(AtnStateKind::RuleStop, Some(0))
19079                .expect("state")
19080                .index(),
19081            2
19082        );
19083        atn.set_rule_to_start_state(vec![0])
19084            .expect("rule start states");
19085        atn.set_rule_to_stop_state(vec![2])
19086            .expect("rule stop states");
19087        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
19088            .expect("transition");
19089        atn.add_transition(
19090            1,
19091            ParserTransitionSpec::Atom {
19092                target: 2,
19093                label: 1,
19094            },
19095        )
19096        .expect("transition");
19097        atn.add_transition(
19098            1,
19099            ParserTransitionSpec::Atom {
19100                target: 2,
19101                label: 2,
19102            },
19103        )
19104        .expect("transition");
19105        let atn = finish_atn(atn);
19106
19107        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
19108        parser.fast_recovery_enabled = false;
19109        let mut visiting = FxHashSet::default();
19110        let mut memo = FxHashMap::default();
19111        let mut expected = ExpectedTokens::default();
19112        let outcomes = parser.recognize_state_fast(
19113            &atn,
19114            FastRecognizeRequest {
19115                state_number: 1,
19116                stop_state: 2,
19117                index: 0,
19118                rule_start_index: 0,
19119                decision_start_index: None,
19120                precedence: 0,
19121                depth: 0,
19122                recovery_symbols: parser.empty_recovery_symbols(),
19123                recovery_state: None,
19124            },
19125            FastRecognizeScratch {
19126                predicate_context: None,
19127                visiting: &mut visiting,
19128                memo: &mut memo,
19129                expected: &mut expected,
19130                native_depth: 0,
19131            },
19132        );
19133
19134        assert!(outcomes.is_empty());
19135        assert_eq!(memo.len(), 1);
19136        assert!(memo.values().next().expect("memo entry").is_empty());
19137
19138        parser.clean_memo_mode = CleanMemoMode::Sparse;
19139        visiting.clear();
19140        memo.clear();
19141        expected = ExpectedTokens::default();
19142        let sparse_outcomes = parser.recognize_state_fast(
19143            &atn,
19144            FastRecognizeRequest {
19145                state_number: 1,
19146                stop_state: 2,
19147                index: 0,
19148                rule_start_index: 0,
19149                decision_start_index: None,
19150                precedence: 0,
19151                depth: 0,
19152                recovery_symbols: parser.empty_recovery_symbols(),
19153                recovery_state: None,
19154            },
19155            FastRecognizeScratch {
19156                predicate_context: None,
19157                visiting: &mut visiting,
19158                memo: &mut memo,
19159                expected: &mut expected,
19160                native_depth: 0,
19161            },
19162        );
19163
19164        assert!(sparse_outcomes.is_empty());
19165        assert!(memo.is_empty());
19166    }
19167
19168    #[test]
19169    fn wildcard_matches_non_eof_only() {
19170        let mut parser = mini_parser(vec![
19171            TestToken::new(1).with_text("x"),
19172            TestToken::eof("parser-test", 1, 1, 1),
19173        ]);
19174        let matched = parser.match_wildcard().expect("wildcard");
19175        assert_eq!(parser.node(matched).text(), "x");
19176        assert!(parser.match_wildcard().is_err());
19177    }
19178
19179    #[test]
19180    fn add_parse_child_records_match_even_without_tree_building() {
19181        // `sync_decision`'s "is the current context empty" flag must reflect real
19182        // matches, not parse-tree children: when `build_parse_trees(false)`,
19183        // `children` stays empty but `has_matched_child` must still flip so nested
19184        // recovery does not wrongly suppress single-token deletion.
19185        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 1, 1, 1)]);
19186        let token = TestToken::new(1).with_text("x");
19187
19188        parser.set_build_parse_trees(false);
19189        let mut ctx = ParserRuleContext::new(0, 0);
19190        assert!(!ctx.has_matched_child());
19191        let child = parser.terminal_tree(token.id);
19192        parser.add_parse_child(&mut ctx, child);
19193        // Tree building is off, so no child is stored...
19194        assert_eq!(ctx.child_count(), 0);
19195        assert_eq!(parser.parse_tree_storage().node_count(), 0);
19196        // ...but the match is recorded, so the context is no longer "empty".
19197        assert!(ctx.has_matched_child());
19198
19199        // With tree building on, the child is stored and the match is recorded.
19200        parser.set_build_parse_trees(true);
19201        let mut ctx = ParserRuleContext::new(0, 0);
19202        let child = parser.terminal_tree(token.id);
19203        parser.add_parse_child(&mut ctx, child);
19204        assert_eq!(ctx.child_count(), 1);
19205        assert!(ctx.has_matched_child());
19206    }
19207
19208    #[test]
19209    fn disabled_tree_building_does_not_grow_flat_storage() {
19210        let mut parser = mini_parser(vec![
19211            TestToken::new(1).with_text("x"),
19212            TestToken::new(1).with_text("y"),
19213            TestToken::eof("parser-test", 2, 1, 2),
19214        ]);
19215        parser.set_build_parse_trees(false);
19216        let mut context = ParserRuleContext::new(0, -1);
19217
19218        for _ in 0..2 {
19219            let child = parser.match_token(1).expect("token should match");
19220            parser.add_parse_child(&mut context, child);
19221        }
19222        let current = parser.input.lt_id(1).expect("EOF token");
19223        let error = parser.error_tree(current);
19224        parser.add_parse_child(&mut context, error);
19225        let root = parser.rule_node(context);
19226
19227        assert_eq!(
19228            parser.parse_tree_storage().stats(),
19229            ParseTreeStats::default()
19230        );
19231        assert!(
19232            parser
19233                .parse_tree_storage()
19234                .node(parser.token_store(), root)
19235                .is_none(),
19236            "the no-tree sentinel must not resolve to stored data"
19237        );
19238    }
19239
19240    #[test]
19241    fn disabled_tree_building_skips_recognition_rule_node_storage() {
19242        let atn = ordinary_star_loop_atn();
19243        let mut parser = mini_parser(repeated_x_tokens(3));
19244        parser.set_build_parse_trees(false);
19245
19246        parser
19247            .parse_atn_rule(&atn, 0)
19248            .expect("ordinary repetition should parse without a tree");
19249
19250        assert_eq!(parser.input.index(), 3);
19251        assert!(parser.recognition_arena.nodes.is_empty());
19252        assert!(parser.recognition_arena.seq_links.is_empty());
19253        assert!(parser.recognition_arena.deferred_nodes.is_empty());
19254        assert!(parser.recognition_arena.deferred_rules.is_empty());
19255        assert!(!parser.fast_token_nodes_enabled);
19256        assert!(parser.fast_recognize_scratch.memo.is_empty());
19257    }
19258
19259    #[test]
19260    fn parser_interprets_simple_atn_rule() {
19261        let atn = token_then_eof_atn();
19262        let mut parser = mini_parser(vec![
19263            TestToken::new(1).with_text("x"),
19264            TestToken::eof("parser-test", 1, 1, 1),
19265        ]);
19266
19267        let tree = parser
19268            .parse_atn_rule(&atn, 0)
19269            .expect("artificial parser rule should parse");
19270        assert_eq!(parser.node(tree).text(), "x<EOF>");
19271        assert_eq!(parser.number_of_syntax_errors(), 0);
19272        assert_eq!(
19273            parser
19274                .node(tree)
19275                .first_rule_stop(0)
19276                .expect("rule should stop at EOF")
19277                .token_type(),
19278            TOKEN_EOF
19279        );
19280
19281        let mut parser = mini_parser(vec![
19282            TestToken::new(1).with_text("x"),
19283            TestToken::eof("parser-test", 1, 1, 1),
19284        ]);
19285        let (tree, actions) = parser
19286            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19287            .expect("runtime-option parser rule should parse");
19288        assert!(actions.is_empty());
19289        assert_eq!(
19290            parser
19291                .node(tree)
19292                .first_rule_stop(0)
19293                .expect("rule should stop at EOF")
19294                .token_type(),
19295            TOKEN_EOF
19296        );
19297    }
19298
19299    #[test]
19300    fn runtime_options_default_ignores_noop_action_transitions() {
19301        let atn = noop_action_then_token_then_eof_atn();
19302        let mut parser = mini_parser(vec![
19303            TestToken::new(1).with_text("x"),
19304            TestToken::eof("parser-test", 1, 1, 1),
19305        ]);
19306
19307        let (tree, actions) = parser
19308            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19309            .expect("no-op parser action should not force action replay");
19310
19311        assert_eq!(parser.node(tree).text(), "x<EOF>");
19312        assert!(
19313            actions.is_empty(),
19314            "action_index=None transitions are ANTLR metadata, not replay actions"
19315        );
19316        assert_eq!(parser.number_of_syntax_errors(), 0);
19317    }
19318
19319    #[test]
19320    fn parser_exposes_buffered_token_stream_after_parse() {
19321        let atn = token_then_eof_atn();
19322        let mut parser = mini_parser(vec![
19323            TestToken::new(1).with_text("x"),
19324            TestToken::eof("parser-test", 1, 1, 1),
19325        ]);
19326
19327        let tree = parser
19328            .parse_atn_rule(&atn, 0)
19329            .expect("artificial parser rule should parse");
19330        assert_eq!(parser.node(tree).text(), "x<EOF>");
19331
19332        let stream = parser.token_stream();
19333        let source_index_after_parse = stream.token_source().index;
19334        let buffered = stream.tokens().collect::<Vec<_>>();
19335        assert_eq!(buffered.len(), 2);
19336        assert_eq!(buffered[0].text(), Some("x"));
19337        assert_eq!(buffered[0].token_id().index(), 0);
19338        assert_eq!(buffered[1].token_type(), TOKEN_EOF);
19339        assert_eq!(stream.token_source().index, source_index_after_parse);
19340        drop(buffered);
19341
19342        let stream = parser.into_token_stream();
19343        assert_eq!(stream.token_source().index, source_index_after_parse);
19344        assert_eq!(
19345            stream.tokens().next().expect("first token").text(),
19346            Some("x")
19347        );
19348        assert_eq!(
19349            stream.tokens().nth(1).expect("EOF token").token_type(),
19350            TOKEN_EOF
19351        );
19352    }
19353
19354    #[test]
19355    fn parsed_file_exposes_all_buffered_tokens() {
19356        let atn = token_then_eof_atn();
19357        let mut parser = mini_parser(vec![
19358            TestToken::new(99)
19359                .with_text(" comment")
19360                .with_channel(HIDDEN_CHANNEL),
19361            TestToken::new(1).with_text("x"),
19362            TestToken::eof("parser-test", 9, 1, 9),
19363        ]);
19364
19365        let tree = parser
19366            .parse_atn_rule(&atn, 0)
19367            .expect("artificial parser rule should parse");
19368        let parsed = parser.into_parsed_file(tree);
19369
19370        // Snapshot the full buffered stream — hidden-channel comment, default-channel token, EOF —
19371        // as (type, channel, text) triples; contents make the count self-evident.
19372        insta::assert_debug_snapshot!(
19373            "parsed_file_exposes_all_buffered_tokens",
19374            parsed
19375                .tokens()
19376                .iter()
19377                .map(|token| (token.token_type(), token.channel(), token.text()))
19378                .collect::<Vec<_>>()
19379        );
19380        assert_eq!(parsed.tokens().into_iter().count(), 3);
19381    }
19382
19383    #[test]
19384    fn parser_syntax_error_count_tracks_interpreted_recovery() {
19385        let atn = token_then_eof_atn();
19386        let mut parser = mini_parser(vec![
19387            TestToken::new(1).with_text("x"),
19388            TestToken::new(2).with_text("y"),
19389            TestToken::eof("parser-test", 2, 1, 2),
19390        ]);
19391
19392        let tree = parser
19393            .parse_atn_rule(&atn, 0)
19394            .expect("invalid token should recover into an error node");
19395
19396        assert_eq!(parser.number_of_syntax_errors(), 1);
19397        assert_eq!(
19398            parser
19399                .node(tree)
19400                .first_error_token()
19401                .expect("recovery should embed an error token")
19402                .text(),
19403            Some("y")
19404        );
19405    }
19406
19407    #[test]
19408    fn failed_interpreted_parse_notifies_error_listener() {
19409        let atn = token_then_eof_atn();
19410        let mut parser = mini_parser(vec![
19411            TestToken::new(2)
19412                .with_text("y")
19413                .with_span(0, 0)
19414                .with_byte_span(0, 1)
19415                .with_position(3, 5),
19416            TestToken::eof("parser-test", 1, 1, 1),
19417        ]);
19418        parser.remove_error_listeners();
19419        let diagnostics = Arc::new(Mutex::new(Vec::new()));
19420        parser.add_error_listener(RecordingErrorListener {
19421            diagnostics: Arc::clone(&diagnostics),
19422        });
19423
19424        let error = parser
19425            .parse_atn_rule(&atn, 0)
19426            .expect_err("start-rule mismatch should remain a parser error");
19427
19428        assert_eq!(parser.number_of_syntax_errors(), 1);
19429        assert!(matches!(&error, AntlrError::ParserError { .. }));
19430        insta::assert_debug_snapshot!(
19431            "failed_interpreted_parse_notifies_error_listener",
19432            *diagnostics.lock().expect("recorded diagnostics lock")
19433        );
19434    }
19435
19436    #[test]
19437    fn adaptive_direct_rule_uses_simulator_decision() {
19438        let atn = two_alt_decision_atn();
19439        let mut simulator = ParserAtnSimulator::new(&atn);
19440        let mut parser = mini_parser(vec![
19441            TestToken::new(2).with_text("y"),
19442            TestToken::eof("parser-test", 1, 1, 1),
19443        ]);
19444
19445        let tree = parser
19446            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19447            .expect("direct adaptive rule should parse");
19448
19449        assert_eq!(parser.node(tree).text(), "y");
19450        assert_eq!(parser.input.index(), 1);
19451    }
19452
19453    #[test]
19454    fn adaptive_direct_rule_restores_input_on_fallback() {
19455        let atn = predicate_after_token_atn();
19456        let mut simulator = ParserAtnSimulator::new(&atn);
19457        let mut parser = mini_parser(vec![
19458            TestToken::new(1).with_text("x"),
19459            TestToken::new(2).with_text("y"),
19460            TestToken::eof("parser-test", 2, 1, 2),
19461        ]);
19462
19463        let tree = parser
19464            .parse_atn_rule_adaptive_or_fallback(&atn, &mut simulator, 0)
19465            .expect("fallback recognizer should parse");
19466
19467        assert_eq!(parser.node(tree).text(), "xy");
19468        assert_eq!(parser.input.index(), 2);
19469        let stats = parser.parse_tree_storage().stats();
19470        assert_eq!(stats.nodes, parser.node(tree).descendants().count());
19471        assert_eq!(stats.edges, stats.nodes.saturating_sub(1));
19472        assert_eq!(stats.scratch_links, 0);
19473    }
19474
19475    #[test]
19476    fn unknown_predicate_policy_defaults_to_assume_true() {
19477        let atn = predicate_after_token_atn();
19478        let mut parser = mini_parser(vec![
19479            TestToken::new(1).with_text("x"),
19480            TestToken::new(2).with_text("y"),
19481            TestToken::eof("parser-test", 2, 1, 2),
19482        ]);
19483
19484        let (tree, _) = parser
19485            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19486            .expect("unknown predicate should pass under the default policy");
19487
19488        assert_eq!(parser.node(tree).text(), "xy");
19489        assert_eq!(parser.number_of_syntax_errors(), 0);
19490    }
19491
19492    #[test]
19493    fn private_context_alt_tracking_keeps_fast_predicate_recognition() {
19494        let atn = predicate_gated_same_lookahead_atn([0, 1]);
19495        let mut parser = mini_parser(vec![
19496            TestToken::new(1).with_text("x"),
19497            TestToken::eof("parser-test", 1, 1, 1),
19498        ]);
19499
19500        let (tree, _) = parser
19501            .parse_atn_rule_with_runtime_options(
19502                &atn,
19503                0,
19504                ParserRuntimeOptions {
19505                    predicates: &[
19506                        (0, 0, ParserPredicate::False),
19507                        (0, 1, ParserPredicate::True),
19508                    ],
19509                    track_context_alt_numbers: true,
19510                    ..ParserRuntimeOptions::default()
19511                },
19512            )
19513            .expect("the second predicate-gated alternative should match");
19514
19515        let root = parser.node(tree).as_rule().expect("entry result is a rule");
19516        insta::assert_debug_snapshot!(
19517            "private_context_alt_tracking_keeps_fast_predicate_recognition",
19518            (root.alt_number(), root.context_alt_number(), root.text())
19519        );
19520        assert_eq!(parser.number_of_syntax_errors(), 0);
19521        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&false));
19522        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 1)), Some(&true));
19523    }
19524
19525    #[test]
19526    fn nested_interpreted_parse_preserves_prior_unknown_predicate_hits() {
19527        // A generated parent may record an unknown-predicate coordinate, then
19528        // descend into an interpreted child. The child's interpreter entry must
19529        // not wipe the parent's recorded hit before the top-level surfaces it.
19530        let atn = token_then_eof_atn();
19531        let mut parser = mini_parser(vec![
19532            TestToken::new(1).with_text("x"),
19533            TestToken::eof("parser-test", 1, 1, 1),
19534        ]);
19535
19536        // Simulate the parent having recorded a fail-loud coordinate.
19537        parser.unknown_predicate_hits.push((7, 3));
19538
19539        // Run an interpreted child parse that records no coordinate of its own.
19540        parser
19541            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19542            .expect("child rule parses");
19543
19544        // The parent's coordinate must still be present for the top-level entry.
19545        let error = parser
19546            .take_unknown_semantic_error()
19547            .expect("parent's recorded coordinate must survive the nested interpreted parse");
19548        let AntlrError::Unsupported(message) = error else {
19549            panic!("expected AntlrError::Unsupported, got {error:?}");
19550        };
19551        assert!(message.contains("pred_index=3"), "message: {message}");
19552    }
19553
19554    #[test]
19555    fn nested_committed_parse_preserves_prior_unhandled_action_hits() {
19556        let atn = token_then_eof_atn();
19557        let mut parser = mini_parser(vec![
19558            TestToken::new(1).with_text("x"),
19559            TestToken::eof("parser-test", 1, 1, 1),
19560        ]);
19561        parser.unhandled_action_hits.push((7, 42));
19562
19563        parser
19564            .parse_atn_rule_with_runtime_options(
19565                &atn,
19566                0,
19567                ParserRuntimeOptions {
19568                    action_indices: &[(usize::MAX, 0)],
19569                    ..ParserRuntimeOptions::default()
19570                },
19571            )
19572            .expect("a child with no action miss must not observe its parent's miss");
19573
19574        let error = parser
19575            .take_unknown_semantic_error()
19576            .expect("the parent's action miss must survive the nested committed parse");
19577        let AntlrError::Unsupported(message) = error else {
19578            panic!("expected AntlrError::Unsupported, got {error:?}");
19579        };
19580        assert!(
19581            message.contains("rule_index=7") && message.contains("state=42"),
19582            "message: {message}"
19583        );
19584    }
19585
19586    #[test]
19587    fn unknown_predicate_policy_assume_false_kills_the_guarded_path() {
19588        let atn = predicate_after_token_atn();
19589        let mut parser = mini_parser(vec![
19590            TestToken::new(1).with_text("x"),
19591            TestToken::new(2).with_text("y"),
19592            TestToken::eof("parser-test", 2, 1, 2),
19593        ]);
19594
19595        let result = parser.parse_atn_rule_with_runtime_options(
19596            &atn,
19597            0,
19598            ParserRuntimeOptions {
19599                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
19600                ..ParserRuntimeOptions::default()
19601            },
19602        );
19603
19604        assert!(
19605            result.is_err(),
19606            "the only path is predicate-guarded, so assume-false must fail the parse"
19607        );
19608    }
19609
19610    #[test]
19611    fn predicate_failure_message_keeps_semantic_recovery_path() {
19612        let atn = predicate_after_token_atn();
19613        let mut parser = mini_parser(vec![
19614            TestToken::new(1).with_text("x"),
19615            TestToken::new(2).with_text("y"),
19616            TestToken::eof("parser-test", 2, 1, 2),
19617        ]);
19618
19619        let (tree, _) = parser
19620            .parse_atn_rule_with_runtime_options(
19621                &atn,
19622                0,
19623                ParserRuntimeOptions {
19624                    predicates: &[(
19625                        0,
19626                        0,
19627                        ParserPredicate::FalseWithMessage {
19628                            message: "predicate rejected input",
19629                        },
19630                    )],
19631                    ..ParserRuntimeOptions::default()
19632                },
19633            )
19634            .expect("failure-message predicates recover through the semantic interpreter");
19635
19636        assert_eq!(parser.node(tree).text(), "xy");
19637        assert_eq!(parser.number_of_syntax_errors(), 1);
19638        assert!(
19639            parser.fast_predicate_cache.is_empty(),
19640            "failure-message predicates need the semantic interpreter's recovery outcome"
19641        );
19642    }
19643
19644    #[test]
19645    fn unknown_predicate_policy_error_names_the_coordinate() {
19646        let atn = predicate_after_token_atn();
19647        let mut parser = mini_parser(vec![
19648            TestToken::new(1).with_text("x"),
19649            TestToken::new(2).with_text("y"),
19650            TestToken::eof("parser-test", 2, 1, 2),
19651        ]);
19652
19653        let error = parser
19654            .parse_atn_rule_with_runtime_options(
19655                &atn,
19656                0,
19657                ParserRuntimeOptions {
19658                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19659                    ..ParserRuntimeOptions::default()
19660                },
19661            )
19662            .expect_err("evaluating an unknown predicate under Error policy must fail");
19663
19664        let AntlrError::Unsupported(message) = error else {
19665            panic!("expected AntlrError::Unsupported, got {error:?}");
19666        };
19667        assert!(
19668            message.contains("unsupported semantic predicate"),
19669            "message should name the failure class: {message}"
19670        );
19671        assert!(
19672            message.contains("pred_index=0"),
19673            "message should carry the coordinate: {message}"
19674        );
19675    }
19676
19677    #[test]
19678    fn fail_loud_hits_do_not_leak_into_a_reused_interpreter_parse() {
19679        // A parser reused after a fail-loud parse must not carry the old
19680        // coordinates into a later parse. The fail-loud return keeps the hits
19681        // (so a generated parent can surface a recovered child's coordinate),
19682        // and the next parse's entry stashes/replaces them, so a subsequent
19683        // clean parse surfaces no stale error.
19684        let atn = predicate_after_token_atn();
19685        let mut parser = mini_parser(vec![
19686            TestToken::new(1).with_text("x"),
19687            TestToken::new(2).with_text("y"),
19688            TestToken::eof("parser-test", 2, 1, 2),
19689        ]);
19690
19691        parser
19692            .parse_atn_rule_with_runtime_options(
19693                &atn,
19694                0,
19695                ParserRuntimeOptions {
19696                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19697                    ..ParserRuntimeOptions::default()
19698                },
19699            )
19700            .expect_err("first parse fails loud under the Error policy");
19701
19702        // The failed parse kept its coordinate on the parser (so a generated
19703        // parent could surface a recovered child). A top-level reuse resets the
19704        // hits — generated parsers call `reset_unknown_semantic_hits` at their
19705        // public entry; direct interpreter-API callers do the same.
19706        parser.reset_unknown_semantic_hits();
19707        assert!(
19708            parser.take_unknown_semantic_error().is_none(),
19709            "reset must drop stale unknown-predicate coordinates before a reused parse"
19710        );
19711    }
19712
19713    #[derive(Debug, Default)]
19714    struct RecordingHooks {
19715        predicates: Vec<(usize, usize, usize, Option<String>)>,
19716        actions: Vec<(usize, String, Option<String>)>,
19717        action_trees: Vec<Option<String>>,
19718    }
19719
19720    impl SemanticHooks for RecordingHooks {
19721        fn sempred<S>(
19722            &mut self,
19723            ctx: &mut ParserSemCtx<'_, S>,
19724            rule_index: usize,
19725            pred_index: usize,
19726        ) -> Option<bool>
19727        where
19728            S: TokenSource,
19729        {
19730            self.predicates.push((
19731                ctx.input_index(),
19732                rule_index,
19733                pred_index,
19734                ctx.token_text(1)
19735                    .and_then(|token| token.text().map(str::to_owned)),
19736            ));
19737            Some(true)
19738        }
19739
19740        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19741        where
19742            S: TokenSource,
19743        {
19744            self.actions.push((
19745                action.source_state(),
19746                ctx.action_text(),
19747                ctx.rule_name().map(str::to_owned),
19748            ));
19749            self.action_trees.push(ctx.tree().map(Node::text));
19750            true
19751        }
19752    }
19753
19754    #[derive(Debug, Default)]
19755    struct StatefulActionHooks {
19756        entered: bool,
19757        events: Vec<String>,
19758    }
19759
19760    impl SemanticHooks for StatefulActionHooks {
19761        fn sempred<S>(
19762            &mut self,
19763            _ctx: &mut ParserSemCtx<'_, S>,
19764            _rule_index: usize,
19765            _pred_index: usize,
19766        ) -> Option<bool>
19767        where
19768            S: TokenSource,
19769        {
19770            self.events.push(format!("predicate:{}", self.entered));
19771            Some(self.entered)
19772        }
19773
19774        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19775        where
19776            S: TokenSource,
19777        {
19778            self.events.push(format!(
19779                "action:{}",
19780                action
19781                    .action_index()
19782                    .map_or_else(|| "legacy".to_owned(), |index| index.to_string())
19783            ));
19784            self.entered = true;
19785            true
19786        }
19787    }
19788
19789    #[derive(Debug, Default)]
19790    struct InitOrderingHooks {
19791        initialized: bool,
19792        events: Vec<String>,
19793    }
19794
19795    impl SemanticHooks for InitOrderingHooks {
19796        fn sempred<S>(
19797            &mut self,
19798            _ctx: &mut ParserSemCtx<'_, S>,
19799            _rule_index: usize,
19800            _pred_index: usize,
19801        ) -> Option<bool>
19802        where
19803            S: TokenSource,
19804        {
19805            self.events.push(format!("predicate:{}", self.initialized));
19806            Some(self.initialized)
19807        }
19808
19809        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19810        where
19811            S: TokenSource,
19812        {
19813            if action.is_rule_init() {
19814                self.initialized = true;
19815                self.events.push("init".to_owned());
19816            } else {
19817                self.events.push(format!(
19818                    "action:{}:initialized={}",
19819                    action
19820                        .action_index()
19821                        .map_or_else(|| "legacy".to_owned(), |index| index.to_string()),
19822                    self.initialized
19823                ));
19824            }
19825            true
19826        }
19827    }
19828
19829    #[derive(Debug, Default)]
19830    struct ActionContextHooks {
19831        actions: Vec<(usize, Option<i64>, Option<usize>)>,
19832    }
19833
19834    impl SemanticHooks for ActionContextHooks {
19835        fn action<S>(&mut self, ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19836        where
19837            S: TokenSource,
19838        {
19839            self.actions.push((
19840                action.action_index().unwrap_or(usize::MAX),
19841                ctx.local_int_arg(),
19842                action.stop_index(),
19843            ));
19844            true
19845        }
19846    }
19847
19848    #[derive(Debug, Default)]
19849    struct DecliningActionHooks {
19850        actions: Vec<usize>,
19851    }
19852
19853    impl SemanticHooks for DecliningActionHooks {
19854        fn action<S>(&mut self, _ctx: &mut ParserSemCtx<'_, S>, action: ParserAction) -> bool
19855        where
19856            S: TokenSource,
19857        {
19858            self.actions.push(action.source_state());
19859            false
19860        }
19861    }
19862
19863    #[derive(Debug, Default)]
19864    struct ForcedSecondAlternativeHooks {
19865        decisions: Vec<(usize, usize, usize)>,
19866    }
19867
19868    impl SemanticHooks for ForcedSecondAlternativeHooks {
19869        fn observes_parser_decisions(&self) -> bool {
19870            true
19871        }
19872
19873        fn parser_decision_override(
19874            &mut self,
19875            decision: usize,
19876            input_index: usize,
19877            alternative_count: usize,
19878        ) -> Option<usize> {
19879            self.decisions
19880                .push((decision, input_index, alternative_count));
19881            Some(2)
19882        }
19883    }
19884
19885    struct RecordingParseListener {
19886        events: Arc<Mutex<Vec<String>>>,
19887    }
19888
19889    impl ParseListener for RecordingParseListener {
19890        fn enter_every_rule(&mut self, event: &EnterRuleEvent<'_>) -> Result<(), AntlrError> {
19891            self.events
19892                .lock()
19893                .expect("parse-listener event lock")
19894                .push(format!("enter:{}", event.rule_index));
19895            Ok(())
19896        }
19897
19898        fn exit_every_rule(&mut self, rule_index: usize) {
19899            self.events
19900                .lock()
19901                .expect("parse-listener event lock")
19902                .push(format!("exit:{rule_index}"));
19903        }
19904    }
19905
19906    #[derive(Debug, Default)]
19907    struct RejectingPredicateHooks {
19908        predicates: Vec<(usize, usize, usize, Option<String>)>,
19909    }
19910
19911    impl SemanticHooks for RejectingPredicateHooks {
19912        fn sempred<S>(
19913            &mut self,
19914            ctx: &mut ParserSemCtx<'_, S>,
19915            rule_index: usize,
19916            pred_index: usize,
19917        ) -> Option<bool>
19918        where
19919            S: TokenSource,
19920        {
19921            self.predicates.push((
19922                ctx.input_index(),
19923                rule_index,
19924                pred_index,
19925                ctx.token_text(1)
19926                    .and_then(|token| token.text().map(str::to_owned)),
19927            ));
19928            Some(false)
19929        }
19930    }
19931
19932    #[test]
19933    fn fast_predicate_cache_replays_hook_once_per_coordinate_and_input() {
19934        let atn = predicate_gated_same_lookahead_atn([0, 0]);
19935        let mut parser = mini_parser_with_hooks(
19936            vec![
19937                TestToken::new(1).with_text("x"),
19938                TestToken::eof("parser-test", 1, 1, 1),
19939            ],
19940            RecordingHooks::default(),
19941        );
19942
19943        let (tree, _) = parser
19944            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
19945            .expect("both alternatives share one replay-safe predicate result");
19946
19947        assert_eq!(parser.node(tree).text(), "x<EOF>");
19948        assert_eq!(
19949            parser.semantic_hooks.predicates,
19950            vec![(0, 0, 0, Some("x".to_owned()))]
19951        );
19952        assert_eq!(parser.fast_predicate_cache.get(&(0, 0, 0)), Some(&true));
19953    }
19954
19955    #[test]
19956    fn semantic_hook_handles_unknown_predicate_before_error_policy() {
19957        let atn = predicate_after_token_atn();
19958        let mut parser = mini_parser_with_hooks(
19959            vec![
19960                TestToken::new(1).with_text("x"),
19961                TestToken::new(2).with_text("y"),
19962                TestToken::eof("parser-test", 2, 1, 2),
19963            ],
19964            RecordingHooks::default(),
19965        );
19966
19967        let (tree, _) = parser
19968            .parse_atn_rule_with_runtime_options(
19969                &atn,
19970                0,
19971                ParserRuntimeOptions {
19972                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
19973                    ..ParserRuntimeOptions::default()
19974                },
19975            )
19976            .expect("hook supplies the missing predicate result");
19977
19978        assert_eq!(parser.node(tree).text(), "xy");
19979        assert_eq!(
19980            parser.semantic_hooks.predicates,
19981            vec![(1, 0, 0, Some("y".to_owned()))]
19982        );
19983        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&true));
19984    }
19985
19986    #[test]
19987    fn runtime_options_default_preserves_semantic_hook_predicates() {
19988        let atn = predicate_after_token_atn();
19989        let mut parser = mini_parser_with_hooks(
19990            vec![
19991                TestToken::new(1).with_text("x"),
19992                TestToken::new(2).with_text("y"),
19993                TestToken::eof("parser-test", 2, 1, 2),
19994            ],
19995            RejectingPredicateHooks::default(),
19996        );
19997
19998        let result =
19999            parser.parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default());
20000
20001        assert!(
20002            result.is_err(),
20003            "default runtime options must not bypass semantic hooks for predicate ATNs"
20004        );
20005        assert_eq!(
20006            parser.semantic_hooks.predicates,
20007            vec![(1, 0, 0, Some("y".to_owned()))]
20008        );
20009        assert_eq!(parser.fast_predicate_cache.get(&(1, 0, 0)), Some(&false));
20010    }
20011
20012    #[test]
20013    fn committed_action_runs_before_later_predicate() {
20014        let atn = committed_action_then_predicate_atn();
20015        let mut parser = mini_parser_with_hooks(
20016            vec![
20017                TestToken::new(1).with_text("x"),
20018                TestToken::eof("parser-test", 1, 1, 1),
20019            ],
20020            StatefulActionHooks::default(),
20021        );
20022
20023        let (tree, deferred_actions) = parser
20024            .parse_atn_rule_with_runtime_options(
20025                &atn,
20026                0,
20027                ParserRuntimeOptions {
20028                    action_indices: &[(0, 7)],
20029                    ..ParserRuntimeOptions::default()
20030                },
20031            )
20032            .expect("the predicate should observe the preceding committed action");
20033
20034        assert_eq!(parser.node(tree).text(), "x<EOF>");
20035        assert!(deferred_actions.is_empty());
20036        assert_eq!(parser.semantic_hooks.events, ["action:7", "predicate:true"]);
20037    }
20038
20039    #[test]
20040    fn committed_action_hook_observes_parameterized_rule_argument() {
20041        let atn = parameterized_child_action_eof_atn();
20042        let rule_args = [ParserRuleArg {
20043            source_state: 0,
20044            rule_index: 1,
20045            value: 42,
20046            inherit_local: false,
20047        }];
20048        let mut parser = mini_parser_with_hooks(
20049            vec![TestToken::eof("parser-test", 0, 1, 0)],
20050            ActionContextHooks::default(),
20051        );
20052
20053        parser
20054            .parse_atn_rule_with_runtime_options(
20055                &atn,
20056                0,
20057                ParserRuntimeOptions {
20058                    action_indices: &[(1, 20), (4, 10)],
20059                    rule_args: &rule_args,
20060                    ..ParserRuntimeOptions::default()
20061                },
20062            )
20063            .expect("the parameterized child should parse");
20064
20065        assert_eq!(
20066            parser.semantic_hooks.actions[0],
20067            (10, Some(42), None),
20068            "the child action should observe its invocation argument"
20069        );
20070    }
20071
20072    #[test]
20073    fn committed_parent_propagates_child_eof_consumption() {
20074        let atn = parameterized_child_action_eof_atn();
20075        let mut parser = mini_parser_with_hooks(
20076            vec![TestToken::eof("parser-test", 0, 1, 0)],
20077            ActionContextHooks::default(),
20078        );
20079
20080        let (tree, _) = parser
20081            .parse_atn_rule_with_runtime_options(
20082                &atn,
20083                0,
20084                ParserRuntimeOptions {
20085                    action_indices: &[(1, 20), (4, 10)],
20086                    ..ParserRuntimeOptions::default()
20087                },
20088            )
20089            .expect("the parent should retain its child's EOF boundary");
20090
20091        assert_eq!(
20092            parser.semantic_hooks.actions[1],
20093            (20, None, Some(0)),
20094            "the parent action should stop at EOF"
20095        );
20096        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20097        assert_eq!(root.stop().map(|token| token.token_type()), Some(TOKEN_EOF));
20098        let child = root
20099            .child_rules(1)
20100            .next()
20101            .expect("the parent should contain the child rule");
20102        assert_eq!(
20103            child.stop().map(|token| token.token_type()),
20104            Some(TOKEN_EOF)
20105        );
20106    }
20107
20108    #[test]
20109    fn committed_walker_does_not_run_action_in_losing_alternative() {
20110        let atn = losing_alternative_action_atn();
20111        let mut parser = mini_parser_with_hooks(
20112            vec![
20113                TestToken::new(2).with_text("y"),
20114                TestToken::eof("parser-test", 1, 1, 1),
20115            ],
20116            StatefulActionHooks::default(),
20117        );
20118
20119        let (tree, deferred_actions) = parser
20120            .parse_atn_rule_with_runtime_options(
20121                &atn,
20122                0,
20123                ParserRuntimeOptions {
20124                    action_indices: &[(2, 0)],
20125                    ..ParserRuntimeOptions::default()
20126                },
20127            )
20128            .expect("the token-led second alternative should be selected");
20129
20130        assert_eq!(parser.node(tree).text(), "y");
20131        assert!(deferred_actions.is_empty());
20132        assert!(parser.semantic_hooks.events.is_empty());
20133    }
20134
20135    #[test]
20136    fn committed_walker_honors_decision_overrides() {
20137        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20138        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
20139        let mut parser = mini_parser_with_hooks(
20140            vec![
20141                TestToken::new(1).with_text("x"),
20142                TestToken::eof("parser-test", 1, 1, 1),
20143            ],
20144            ForcedSecondAlternativeHooks::default(),
20145        );
20146
20147        let (tree, deferred_actions) = parser
20148            .parse_atn_rule_with_runtime_options(
20149                &atn,
20150                0,
20151                ParserRuntimeOptions {
20152                    action_indices: &[(usize::MAX, 0)],
20153                    track_alt_numbers: true,
20154                    predicates: &predicates,
20155                    ..ParserRuntimeOptions::default()
20156                },
20157            )
20158            .expect("the forced second alternative should parse");
20159
20160        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20161        assert_eq!(root.alt_number(), 2);
20162        assert_eq!(root.text(), "x<EOF>");
20163        assert!(deferred_actions.is_empty());
20164        assert_eq!(parser.semantic_hooks.decisions, [(0, 0, 2)]);
20165        assert_eq!(parser.number_of_syntax_errors(), 0);
20166    }
20167
20168    #[test]
20169    fn committed_walker_sll_mode_does_not_report_full_context_diagnostics() {
20170        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20171        let predicates = [(0, 0, ParserPredicate::True), (0, 1, ParserPredicate::True)];
20172        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20173        let mut parser = mini_parser(vec![
20174            TestToken::new(1).with_text("x"),
20175            TestToken::eof("parser-test", 1, 1, 1),
20176        ]);
20177        parser.set_prediction_mode(PredictionMode::Sll);
20178        parser.set_report_diagnostic_errors(true);
20179        parser.remove_error_listeners();
20180        parser.add_error_listener(RecordingErrorListener {
20181            diagnostics: Arc::clone(&diagnostics),
20182        });
20183
20184        let (tree, deferred_actions) = parser
20185            .parse_atn_rule_with_runtime_options(
20186                &atn,
20187                0,
20188                ParserRuntimeOptions {
20189                    action_indices: &[(usize::MAX, 0)],
20190                    predicates: &predicates,
20191                    ..ParserRuntimeOptions::default()
20192                },
20193            )
20194            .expect("SLL prediction should select the first viable alternative");
20195
20196        assert_eq!(parser.node(tree).text(), "x<EOF>");
20197        assert!(deferred_actions.is_empty());
20198        assert_eq!(parser.number_of_syntax_errors(), 0);
20199        assert!(
20200            diagnostics
20201                .lock()
20202                .expect("recorded diagnostics lock")
20203                .is_empty(),
20204            "SLL mode must not retry with full context or report LL diagnostics"
20205        );
20206    }
20207
20208    #[test]
20209    fn committed_walker_filters_diagnostics_after_semantic_selection() {
20210        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20211        let predicates = [
20212            (0, 0, ParserPredicate::False),
20213            (0, 1, ParserPredicate::True),
20214        ];
20215        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20216        let mut parser = mini_parser(vec![
20217            TestToken::new(1).with_text("x"),
20218            TestToken::eof("parser-test", 1, 1, 1),
20219        ]);
20220        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20221        parser.set_report_diagnostic_errors(true);
20222        parser.remove_error_listeners();
20223        parser.add_error_listener(RecordingErrorListener {
20224            diagnostics: Arc::clone(&diagnostics),
20225        });
20226
20227        let (tree, _) = parser
20228            .parse_atn_rule_with_runtime_options(
20229                &atn,
20230                0,
20231                ParserRuntimeOptions {
20232                    action_indices: &[(usize::MAX, 0)],
20233                    track_alt_numbers: true,
20234                    predicates: &predicates,
20235                    ..ParserRuntimeOptions::default()
20236                },
20237            )
20238            .expect("the true predicate should make the second alternative unique");
20239
20240        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20241        assert_eq!(root.alt_number(), 2);
20242        assert!(
20243            diagnostics
20244                .lock()
20245                .expect("recorded diagnostics lock")
20246                .is_empty(),
20247            "predicate filtering made the decision unambiguous"
20248        );
20249    }
20250
20251    #[test]
20252    fn committed_walker_skips_diagnostic_only_predicates_when_reporting_is_disabled() {
20253        let atn = predicate_gated_same_lookahead_atn([0, 1]);
20254        let mut parser = mini_parser_with_hooks(
20255            vec![
20256                TestToken::new(1).with_text("x"),
20257                TestToken::eof("parser-test", 1, 1, 1),
20258            ],
20259            RecordingHooks::default(),
20260        );
20261        parser.set_prediction_mode(PredictionMode::LlExactAmbigDetection);
20262
20263        let (tree, _) = parser
20264            .parse_atn_rule_with_runtime_options(
20265                &atn,
20266                0,
20267                ParserRuntimeOptions {
20268                    action_indices: &[(usize::MAX, 0)],
20269                    track_alt_numbers: true,
20270                    ..ParserRuntimeOptions::default()
20271                },
20272            )
20273            .expect("the first predicate-bearing alternative should parse");
20274
20275        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20276        assert_eq!(root.alt_number(), 1);
20277        assert_eq!(
20278            parser.semantic_hooks.predicates,
20279            [
20280                (0, 0, 0, Some("x".to_owned())),
20281                (0, 0, 0, Some("x".to_owned())),
20282            ],
20283            "diagnostic-only alternatives must not invoke semantic hooks"
20284        );
20285    }
20286
20287    #[test]
20288    fn committed_walker_falls_back_only_to_simulator_viable_alternatives() {
20289        let atn = semantic_fallback_viability_atn();
20290        let predicates = [
20291            (0, 0, ParserPredicate::False),
20292            (0, 1, ParserPredicate::True),
20293        ];
20294        let mut parser = mini_parser(vec![
20295            TestToken::new(1).with_text("a"),
20296            TestToken::new(3).with_text("c"),
20297            TestToken::eof("parser-test", 2, 1, 2),
20298        ]);
20299
20300        let (tree, deferred_actions) = parser
20301            .parse_atn_rule_with_runtime_options(
20302                &atn,
20303                0,
20304                ParserRuntimeOptions {
20305                    action_indices: &[(usize::MAX, 0)],
20306                    track_alt_numbers: true,
20307                    predicates: &predicates,
20308                    ..ParserRuntimeOptions::default()
20309                },
20310            )
20311            .expect("the true A C alternative should survive semantic fallback");
20312
20313        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20314        assert_eq!(root.alt_number(), 3);
20315        assert_eq!(root.text(), "ac<EOF>");
20316        assert!(deferred_actions.is_empty());
20317        assert_eq!(parser.number_of_syntax_errors(), 0);
20318    }
20319
20320    #[test]
20321    fn committed_walker_evaluates_predicates_reached_through_rule_calls() {
20322        let atn = rule_call_predicate_decision_atn();
20323        let predicates = [(1, 0, ParserPredicate::False)];
20324        let mut parser = mini_parser(vec![
20325            TestToken::new(1).with_text("a"),
20326            TestToken::eof("parser-test", 1, 1, 1),
20327        ]);
20328
20329        let (tree, deferred_actions) = parser
20330            .parse_atn_rule_with_runtime_options(
20331                &atn,
20332                0,
20333                ParserRuntimeOptions {
20334                    action_indices: &[(usize::MAX, 0)],
20335                    track_alt_numbers: true,
20336                    predicates: &predicates,
20337                    ..ParserRuntimeOptions::default()
20338                },
20339            )
20340            .expect("the direct caller alternative should survive the false callee predicate");
20341
20342        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20343        assert_eq!(root.alt_number(), 2);
20344        assert_eq!(root.text(), "a<EOF>");
20345        assert_eq!(root.child_rules(1).count(), 0);
20346        assert!(deferred_actions.is_empty());
20347        assert_eq!(parser.number_of_syntax_errors(), 0);
20348    }
20349
20350    #[test]
20351    fn committed_walker_uses_callee_argument_for_prediction_predicates() {
20352        let atn = rule_call_predicate_decision_atn();
20353        let predicates = [(1, 0, ParserPredicate::LocalIntEquals { value: 1 })];
20354        let rule_args = [ParserRuleArg {
20355            source_state: 2,
20356            rule_index: 1,
20357            value: 2,
20358            inherit_local: false,
20359        }];
20360        let mut parser = mini_parser(vec![
20361            TestToken::new(1).with_text("a"),
20362            TestToken::eof("parser-test", 1, 1, 1),
20363        ]);
20364
20365        let (tree, _) = parser
20366            .parse_atn_rule_with_runtime_options(
20367                &atn,
20368                0,
20369                ParserRuntimeOptions {
20370                    action_indices: &[(usize::MAX, 0)],
20371                    track_alt_numbers: true,
20372                    predicates: &predicates,
20373                    rule_args: &rule_args,
20374                    ..ParserRuntimeOptions::default()
20375                },
20376            )
20377            .expect("the direct alternative should survive the false callee predicate");
20378
20379        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20380        assert_eq!(root.alt_number(), 2);
20381        assert_eq!(root.child_rules(1).count(), 0);
20382        assert_eq!(parser.number_of_syntax_errors(), 0);
20383    }
20384
20385    #[test]
20386    fn committed_predicate_star_loop_uses_single_token_deletion() {
20387        let atn = predicate_gated_star_loop_atn();
20388        let predicates = [(0, 0, ParserPredicate::True)];
20389        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20390        let mut parser = mini_parser(vec![
20391            TestToken::new(2).with_text("x"),
20392            TestToken::new(1).with_text("a"),
20393            TestToken::eof("parser-test", 2, 1, 2),
20394        ]);
20395        parser.remove_error_listeners();
20396        parser.add_error_listener(RecordingErrorListener {
20397            diagnostics: Arc::clone(&diagnostics),
20398        });
20399
20400        let (tree, deferred_actions) = parser
20401            .parse_atn_rule_with_runtime_options(
20402                &atn,
20403                0,
20404                ParserRuntimeOptions {
20405                    action_indices: &[(usize::MAX, 0)],
20406                    predicates: &predicates,
20407                    ..ParserRuntimeOptions::default()
20408                },
20409            )
20410            .expect("the loop decision should delete the extraneous token and continue");
20411
20412        assert_eq!(parser.node(tree).text(), "xa<EOF>");
20413        assert!(deferred_actions.is_empty());
20414        assert_eq!(parser.number_of_syntax_errors(), 1);
20415        insta::assert_debug_snapshot!(
20416            "committed_predicate_star_loop_uses_single_token_deletion",
20417            *diagnostics.lock().expect("recorded diagnostics lock")
20418        );
20419    }
20420
20421    #[test]
20422    fn committed_walker_applies_legacy_and_semir_actions_before_indexed_hooks() {
20423        let atn = committed_action_then_predicate_atn();
20424        let member_actions = [ParserMemberAction {
20425            source_state: 0,
20426            member: 0,
20427            delta: 2,
20428        }];
20429        let return_actions = [ParserReturnAction {
20430            source_state: 0,
20431            rule_index: 0,
20432            name: "legacy",
20433            value: 3,
20434        }];
20435        let predicates = [(
20436            0,
20437            0,
20438            ParserPredicate::MemberEquals {
20439                member: 0,
20440                value: 7,
20441                equals: true,
20442            },
20443        )];
20444        let mut ir = SemIr::new();
20445        let semantic_member = ParserMemberAction {
20446            source_state: 0,
20447            member: 0,
20448            delta: 5,
20449        }
20450        .lower_into_semir(&mut ir);
20451        let semantic_return = ParserReturnAction {
20452            source_state: 0,
20453            rule_index: 0,
20454            name: "semantic",
20455            value: 11,
20456        }
20457        .lower_into_semir(&mut ir);
20458        let semantics = ParserSemantics {
20459            ir,
20460            predicates: Vec::new(),
20461            actions: vec![semantic_member, semantic_return],
20462        };
20463        let mut parser = mini_parser_with_hooks(
20464            vec![
20465                TestToken::new(1).with_text("x"),
20466                TestToken::eof("parser-test", 1, 1, 1),
20467            ],
20468            StatefulActionHooks::default(),
20469        );
20470
20471        let (tree, deferred_actions) = parser
20472            .parse_atn_rule_with_runtime_options(
20473                &atn,
20474                0,
20475                ParserRuntimeOptions {
20476                    action_indices: &[(0, 7)],
20477                    predicates: &predicates,
20478                    semantics: Some(&semantics),
20479                    member_actions: &member_actions,
20480                    return_actions: &return_actions,
20481                    ..ParserRuntimeOptions::default()
20482                },
20483            )
20484            .expect("the predicate should observe both committed member actions");
20485
20486        let root = parser.node(tree).as_rule().expect("entry result is a rule");
20487        assert_eq!(root.text(), "x<EOF>");
20488        assert_eq!(root.int_return("legacy"), Some(3));
20489        assert_eq!(root.int_return("semantic"), Some(11));
20490        assert_eq!(parser.int_member(0), Some(7));
20491        assert!(deferred_actions.is_empty());
20492        assert_eq!(parser.semantic_hooks.events, ["action:7"]);
20493        assert_eq!(parser.number_of_syntax_errors(), 0);
20494    }
20495
20496    #[test]
20497    fn committed_walker_runs_action_once_per_star_loop_iteration() {
20498        let atn = committed_action_star_loop_atn();
20499        let mut parser = mini_parser_with_hooks(
20500            vec![
20501                TestToken::new(1).with_text("a"),
20502                TestToken::new(1).with_text("b"),
20503                TestToken::eof("parser-test", 2, 1, 2),
20504            ],
20505            StatefulActionHooks::default(),
20506        );
20507
20508        let (tree, deferred_actions) = parser
20509            .parse_atn_rule_with_runtime_options(
20510                &atn,
20511                0,
20512                ParserRuntimeOptions {
20513                    action_indices: &[(2, 3)],
20514                    ..ParserRuntimeOptions::default()
20515                },
20516            )
20517            .expect("the committed star loop should parse");
20518
20519        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20520        assert!(deferred_actions.is_empty());
20521        assert_eq!(parser.semantic_hooks.events, ["action:3", "action:3"]);
20522    }
20523
20524    #[test]
20525    fn committed_walker_has_no_total_step_cap() {
20526        const TOKEN_COUNT: usize = RECOGNITION_DEPTH_LIMIT + 1;
20527        let atn = committed_action_star_loop_atn();
20528        let mut parser = mini_parser(repeated_x_tokens(TOKEN_COUNT));
20529        parser.set_build_parse_trees(false);
20530
20531        parser
20532            .parse_atn_rule_with_runtime_options(
20533                &atn,
20534                0,
20535                ParserRuntimeOptions {
20536                    action_indices: &[(usize::MAX, 0)],
20537                    ..ParserRuntimeOptions::default()
20538                },
20539            )
20540            .expect("valid committed loops must not have a total-work cap");
20541
20542        assert_eq!(parser.input.index(), TOKEN_COUNT);
20543        assert_eq!(parser.number_of_syntax_errors(), 0);
20544    }
20545
20546    #[test]
20547    fn committed_walker_rejects_non_consuming_cycles() {
20548        let atn = committed_non_consuming_cycle_atn();
20549        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
20550        parser.set_bail_on_error(true);
20551
20552        let error = parser
20553            .parse_atn_rule_with_runtime_options(
20554                &atn,
20555                0,
20556                ParserRuntimeOptions {
20557                    action_indices: &[(usize::MAX, 0)],
20558                    ..ParserRuntimeOptions::default()
20559                },
20560            )
20561            .expect_err("a non-consuming cycle must not spin forever");
20562
20563        assert!(
20564            error.to_string().contains("non-consuming ATN cycle"),
20565            "unexpected error: {error}"
20566        );
20567    }
20568
20569    #[test]
20570    fn deeply_nested_committed_rule_calls_grow_the_stack() {
20571        const DEPTH: usize = 4_096;
20572        const STACK_SIZE: usize = 256 * 1024;
20573        let atn = nested_rule_chain_atn(DEPTH);
20574        std::thread::Builder::new()
20575            .name("nested-committed-rules".to_owned())
20576            .stack_size(STACK_SIZE)
20577            .spawn(move || {
20578                let mut parser = mini_parser(vec![TestToken::new(1).with_text("x")]);
20579                parser.set_build_parse_trees(false);
20580                parser
20581                    .parse_atn_rule_with_runtime_options(
20582                        &atn,
20583                        0,
20584                        ParserRuntimeOptions {
20585                            action_indices: &[(usize::MAX, 0)],
20586                            ..ParserRuntimeOptions::default()
20587                        },
20588                    )
20589                    .expect("nested committed rules should grow the native stack");
20590                assert_eq!(parser.input.index(), 1);
20591            })
20592            .expect("small-stack thread should start")
20593            .join()
20594            .expect("nested committed rules should not overflow their stack");
20595    }
20596
20597    #[test]
20598    fn committed_walker_runs_action_once_per_left_recursive_operator() {
20599        let atn = committed_action_left_recursive_atn();
20600        let mut parser = mini_parser_with_hooks(
20601            vec![
20602                TestToken::new(1).with_text("a"),
20603                TestToken::new(3).with_text("+"),
20604                TestToken::new(1).with_text("b"),
20605                TestToken::new(3).with_text("+"),
20606                TestToken::new(1).with_text("c"),
20607                TestToken::eof("parser-test", 5, 1, 5),
20608            ],
20609            StatefulActionHooks::default(),
20610        );
20611
20612        let (tree, deferred_actions) = parser
20613            .parse_atn_rule_with_runtime_options(
20614                &atn,
20615                0,
20616                ParserRuntimeOptions {
20617                    action_indices: &[(6, 11)],
20618                    ..ParserRuntimeOptions::default()
20619                },
20620            )
20621            .expect("the committed left-recursive rule should parse");
20622
20623        assert_eq!(parser.node(tree).text(), "a+b+c");
20624        assert!(deferred_actions.is_empty());
20625        assert_eq!(parser.semantic_hooks.events, ["action:11", "action:11"]);
20626    }
20627
20628    #[test]
20629    fn committed_left_recursive_depth_cap_keeps_listener_events_balanced() {
20630        let atn = committed_action_left_recursive_atn();
20631        let events = Arc::new(Mutex::new(Vec::new()));
20632        let mut parser = mini_parser(vec![
20633            TestToken::new(1).with_text("a"),
20634            TestToken::new(3).with_text("+"),
20635            TestToken::new(1).with_text("b"),
20636            TestToken::eof("parser-test", 3, 1, 3),
20637        ]);
20638        parser.set_max_rule_depth(Some(1));
20639        parser.add_parse_listener(RecordingParseListener {
20640            events: Arc::clone(&events),
20641        });
20642
20643        let error = parser
20644            .parse_atn_rule_with_runtime_options(
20645                &atn,
20646                0,
20647                ParserRuntimeOptions {
20648                    action_indices: &[(6, 11)],
20649                    ..ParserRuntimeOptions::default()
20650                },
20651            )
20652            .expect_err("the left-recursive expansion should exceed the depth cap");
20653
20654        insta::assert_debug_snapshot!(
20655            "committed_left_recursive_depth_cap_keeps_listener_events_balanced",
20656            (
20657                error.to_string(),
20658                events.lock().expect("parse-listener event lock").as_slice(),
20659            )
20660        );
20661    }
20662
20663    #[test]
20664    fn committed_walker_preserves_nested_rule_listener_events() {
20665        let atn = ordinary_star_loop_atn();
20666        let events = Arc::new(Mutex::new(Vec::new()));
20667        let mut parser = mini_parser(vec![
20668            TestToken::new(1).with_text("a"),
20669            TestToken::new(1).with_text("b"),
20670            TestToken::eof("parser-test", 2, 1, 2),
20671        ]);
20672        parser.add_parse_listener(RecordingParseListener {
20673            events: Arc::clone(&events),
20674        });
20675
20676        let (tree, _) = parser
20677            .parse_atn_rule_with_runtime_options(
20678                &atn,
20679                0,
20680                ParserRuntimeOptions {
20681                    action_indices: &[(usize::MAX, 0)],
20682                    ..ParserRuntimeOptions::default()
20683                },
20684            )
20685            .expect("the committed nested-rule path should parse");
20686
20687        assert_eq!(parser.node(tree).text(), "ab<EOF>");
20688        assert_eq!(
20689            *events.lock().expect("parse-listener event lock"),
20690            [
20691                "enter:0", "enter:1", "exit:1", "enter:1", "exit:1", "exit:0",
20692            ]
20693        );
20694    }
20695
20696    #[test]
20697    fn committed_walker_enforces_rule_depth_cap() {
20698        let atn = ordinary_star_loop_atn();
20699        let mut parser = mini_parser(vec![
20700            TestToken::new(1).with_text("a"),
20701            TestToken::eof("parser-test", 1, 1, 1),
20702        ]);
20703        parser.set_max_rule_depth(Some(1));
20704
20705        let error = parser
20706            .parse_atn_rule_with_runtime_options(
20707                &atn,
20708                0,
20709                ParserRuntimeOptions {
20710                    action_indices: &[(usize::MAX, 0)],
20711                    ..ParserRuntimeOptions::default()
20712                },
20713            )
20714            .expect_err("the nested rule should exceed the committed-path cap");
20715
20716        assert!(
20717            error
20718                .to_string()
20719                .contains("rule nesting depth limit of 1 exceeded"),
20720            "unexpected error: {error}"
20721        );
20722    }
20723
20724    #[test]
20725    fn committed_abort_precedes_and_clears_unhandled_action_error() {
20726        let atn = action_then_nested_rule_atn();
20727        let mut parser = mini_parser_with_hooks(
20728            vec![TestToken::eof("parser-test", 0, 1, 0)],
20729            DecliningActionHooks::default(),
20730        );
20731        parser.set_max_rule_depth(Some(1));
20732
20733        let error = parser
20734            .parse_atn_rule_with_runtime_options(
20735                &atn,
20736                0,
20737                ParserRuntimeOptions {
20738                    action_indices: &[(0, 7)],
20739                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20740                    ..ParserRuntimeOptions::default()
20741                },
20742            )
20743            .expect_err("the recovered child abort must outrank the earlier action miss");
20744
20745        assert_eq!(parser.semantic_hooks.actions, [0]);
20746        assert!(
20747            error
20748                .to_string()
20749                .contains("rule nesting depth limit of 1 exceeded"),
20750            "unexpected error: {error}"
20751        );
20752        assert!(
20753            parser.take_parse_abort().is_none(),
20754            "the returned abort must not remain sticky"
20755        );
20756        assert!(
20757            parser.take_unknown_semantic_error().is_none(),
20758            "the masked action miss must not poison parser reuse"
20759        );
20760    }
20761
20762    #[test]
20763    fn top_level_committed_semantic_error_does_not_poison_reuse() {
20764        let atn = committed_action_then_predicate_atn();
20765        let predicates = [(0, 0, ParserPredicate::True)];
20766        let mut parser = mini_parser_with_hooks(
20767            vec![
20768                TestToken::new(1).with_text("x"),
20769                TestToken::eof("parser-test", 1, 1, 1),
20770            ],
20771            DecliningActionHooks::default(),
20772        );
20773
20774        let error = parser
20775            .parse_atn_rule_with_runtime_options(
20776                &atn,
20777                0,
20778                ParserRuntimeOptions {
20779                    action_indices: &[(0, 7)],
20780                    predicates: &predicates,
20781                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20782                    ..ParserRuntimeOptions::default()
20783                },
20784            )
20785            .expect_err("the declined committed action must fail loud");
20786        assert!(
20787            error.to_string().contains("unhandled semantic action"),
20788            "unexpected error: {error}"
20789        );
20790
20791        parser.input.seek(0);
20792        let (tree, _) = parser
20793            .parse_atn_rule_with_runtime_options(
20794                &atn,
20795                0,
20796                ParserRuntimeOptions {
20797                    predicates: &predicates,
20798                    ..ParserRuntimeOptions::default()
20799                },
20800            )
20801            .expect("a clean interpreted reuse must not observe the prior action miss");
20802
20803        assert_eq!(parser.node(tree).text(), "x<EOF>");
20804        assert!(
20805            parser.take_unknown_semantic_error().is_none(),
20806            "the returned top-level semantic error must drain its recorded hit"
20807        );
20808    }
20809
20810    #[test]
20811    fn committed_walker_runs_handled_rule_init_before_indexed_action() {
20812        let atn = committed_action_then_predicate_atn();
20813        let mut parser = mini_parser_with_hooks(
20814            vec![
20815                TestToken::new(1).with_text("x"),
20816                TestToken::eof("parser-test", 1, 1, 1),
20817            ],
20818            InitOrderingHooks::default(),
20819        );
20820
20821        let (_, deferred_actions) = parser
20822            .parse_atn_rule_with_runtime_options(
20823                &atn,
20824                0,
20825                ParserRuntimeOptions {
20826                    init_action_rules: &[0],
20827                    action_indices: &[(0, 7)],
20828                    ..ParserRuntimeOptions::default()
20829                },
20830            )
20831            .expect("the named action should observe rule-init state");
20832
20833        assert!(deferred_actions.is_empty());
20834        assert_eq!(
20835            parser.semantic_hooks.events,
20836            ["init", "action:7:initialized=true", "predicate:true",]
20837        );
20838    }
20839
20840    #[test]
20841    fn committed_walker_defers_unhandled_rule_init_for_legacy_replay() {
20842        let atn = token_then_eof_atn();
20843        let mut parser = mini_parser(vec![
20844            TestToken::new(1).with_text("x"),
20845            TestToken::eof("parser-test", 1, 1, 1),
20846        ]);
20847
20848        let (_, deferred_actions) = parser
20849            .parse_atn_rule_with_runtime_options(
20850                &atn,
20851                0,
20852                ParserRuntimeOptions {
20853                    init_action_rules: &[0],
20854                    action_indices: &[(usize::MAX, 0)],
20855                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
20856                    ..ParserRuntimeOptions::default()
20857                },
20858            )
20859            .expect("a declined init should remain available for legacy replay");
20860
20861        assert_eq!(
20862            deferred_actions,
20863            [ParserAction::new_rule_init(0, 0, Some(0))]
20864        );
20865    }
20866
20867    #[test]
20868    fn committed_walker_dispatches_recovery_diagnostics() {
20869        let atn = noop_action_then_token_then_eof_atn();
20870        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20871        let mut parser = mini_parser_with_hooks(
20872            vec![
20873                TestToken::new(1).with_text("x"),
20874                TestToken::new(2).with_text("y"),
20875                TestToken::eof("parser-test", 2, 1, 2),
20876            ],
20877            StatefulActionHooks::default(),
20878        );
20879        parser.remove_error_listeners();
20880        parser.add_error_listener(RecordingErrorListener {
20881            diagnostics: Arc::clone(&diagnostics),
20882        });
20883
20884        let (tree, _) = parser
20885            .parse_atn_rule_with_runtime_options(
20886                &atn,
20887                0,
20888                ParserRuntimeOptions {
20889                    action_indices: &[(0, 5)],
20890                    ..ParserRuntimeOptions::default()
20891                },
20892            )
20893            .expect("the committed rule should recover");
20894
20895        assert_eq!(parser.node(tree).text(), "xy<EOF>");
20896        assert_eq!(parser.number_of_syntax_errors(), 1);
20897        insta::assert_debug_snapshot!(
20898            "committed_walker_dispatches_recovery_diagnostics",
20899            *diagnostics.lock().expect("recorded diagnostics lock")
20900        );
20901    }
20902
20903    #[test]
20904    fn committed_bail_error_notifies_error_listener() {
20905        let atn = noop_action_then_token_then_eof_atn();
20906        let diagnostics = Arc::new(Mutex::new(Vec::new()));
20907        let mut parser = mini_parser(vec![
20908            TestToken::new(2)
20909                .with_text("y")
20910                .with_span(0, 0)
20911                .with_byte_span(0, 1)
20912                .with_position(3, 5),
20913            TestToken::eof("parser-test", 1, 1, 1),
20914        ]);
20915        parser.set_bail_on_error(true);
20916        parser.remove_error_listeners();
20917        parser.add_error_listener(RecordingErrorListener {
20918            diagnostics: Arc::clone(&diagnostics),
20919        });
20920
20921        let error = parser
20922            .parse_atn_rule_with_runtime_options(
20923                &atn,
20924                0,
20925                ParserRuntimeOptions {
20926                    action_indices: &[(0, 5)],
20927                    ..ParserRuntimeOptions::default()
20928                },
20929            )
20930            .expect_err("bail mode must return the committed token mismatch");
20931        let diagnostics = diagnostics
20932            .lock()
20933            .expect("recorded diagnostics lock")
20934            .clone();
20935
20936        insta::assert_debug_snapshot!(
20937            "committed_bail_error_notifies_error_listener",
20938            (error, diagnostics)
20939        );
20940    }
20941
20942    #[test]
20943    fn semantic_hook_handles_committed_parser_action() {
20944        let atn = token_then_eof_atn();
20945        let mut parser = mini_parser_with_hooks(
20946            vec![
20947                TestToken::new(1).with_text("x"),
20948                TestToken::eof("parser-test", 1, 1, 1),
20949            ],
20950            RecordingHooks::default(),
20951        );
20952        let (tree, _) = parser
20953            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
20954            .expect("rule parses before action hook is tested");
20955
20956        assert!(parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20957        assert_eq!(
20958            parser.semantic_hooks.actions,
20959            vec![(42, "x".to_owned(), Some("s".to_owned()))]
20960        );
20961        assert_eq!(
20962            parser.semantic_hooks.action_trees,
20963            [Some("x<EOF>".to_owned())]
20964        );
20965    }
20966
20967    #[test]
20968    fn unhandled_committed_action_fails_loud_under_error_policy() {
20969        // An action offered to the hook that no hook handles (returns false)
20970        // must be recorded and surfaced as `AntlrError::Unsupported` under the
20971        // Error policy, so a `hook`-disposed action is not silently dropped.
20972        let mut parser = mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
20973        parser.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
20974        let tree = parser.rule_node(ParserRuleContext::new(0, -1));
20975
20976        // DecliningHooks::action returns false (unhandled).
20977        assert!(!parser.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20978
20979        let error = parser
20980            .take_unknown_semantic_error()
20981            .expect("an unhandled committed action under Error policy must fail loud");
20982        let AntlrError::Unsupported(message) = error else {
20983            panic!("expected AntlrError::Unsupported, got {error:?}");
20984        };
20985        assert!(
20986            message.contains("unhandled semantic action") && message.contains("state=42"),
20987            "message should name the dropped action coordinate: {message}"
20988        );
20989
20990        // Under the default (assume-true) policy the same miss is not recorded.
20991        let mut lenient =
20992            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
20993        let tree = lenient.rule_node(ParserRuleContext::new(0, -1));
20994        assert!(!lenient.parser_action_hook(ParserAction::new(42, 0, 0, Some(0)), tree));
20995        assert!(lenient.take_unknown_semantic_error().is_none());
20996    }
20997
20998    #[test]
20999    fn translated_predicate_is_unaffected_by_error_policy() {
21000        let atn = predicate_after_token_atn();
21001        let mut parser = mini_parser(vec![
21002            TestToken::new(1).with_text("x"),
21003            TestToken::new(2).with_text("y"),
21004            TestToken::eof("parser-test", 2, 1, 2),
21005        ]);
21006
21007        let (tree, _) = parser
21008            .parse_atn_rule_with_runtime_options(
21009                &atn,
21010                0,
21011                ParserRuntimeOptions {
21012                    predicates: &[(0, 0, ParserPredicate::True)],
21013                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21014                    ..ParserRuntimeOptions::default()
21015                },
21016            )
21017            .expect("a predicate covered by the table is not an unknown coordinate");
21018
21019        assert_eq!(parser.node(tree).text(), "xy");
21020    }
21021
21022    /// Stack-valued member statements must execute on the parser's speculative
21023    /// replay path, not just the lexer's committed one (issue #206). This drives
21024    /// `apply_member_actions` -> `ParserTableSemCtx` -> `MemberEnv` directly,
21025    /// which is the path a generated parser's `@members` stack state takes.
21026    #[test]
21027    fn parser_speculative_replay_threads_stack_member_state() {
21028        let mut ir = SemIr::new();
21029        let one = ir.expr(PExpr::Int(1));
21030        let push = ir.stmt(AStmt::PushMember(0, one));
21031        let pop = ir.stmt(AStmt::PopMember(0));
21032        let semantics = ParserSemantics {
21033            ir,
21034            predicates: Vec::new(),
21035            actions: vec![
21036                ParserSemanticAction {
21037                    source_state: 1,
21038                    rule_index: usize::MAX,
21039                    stmt: push,
21040                    speculative: true,
21041                },
21042                ParserSemanticAction {
21043                    source_state: 2,
21044                    rule_index: usize::MAX,
21045                    stmt: pop,
21046                    speculative: true,
21047                },
21048            ],
21049        };
21050
21051        // Replaying the push state must be visible to a later read...
21052        let pushed = member_values_after_action(1, &[], Some(&semantics), &MemberEnv::new());
21053        assert_eq!(pushed.stack_top(0), Some(1));
21054        assert_eq!(pushed.stack_len(0), 1);
21055
21056        // ...and must not mutate the caller's env: speculative paths are
21057        // path-local, so an abandoned branch cannot leak state to its sibling.
21058        assert_eq!(MemberEnv::new().stack_len(0), 0);
21059
21060        // Replaying the pop state restores the empty, canonical env, so the
21061        // resulting memo key matches an equivalent untouched path.
21062        let popped = member_values_after_action(2, &[], Some(&semantics), &pushed);
21063        assert_eq!(popped.stack_top(0), None);
21064        assert_eq!(popped, MemberEnv::new(), "emptied stack must canonicalize");
21065
21066        // An unbalanced pop is a defined no-op rather than a panic.
21067        let underflowed = member_values_after_action(2, &[], Some(&semantics), &MemberEnv::new());
21068        assert_eq!(underflowed, MemberEnv::new());
21069    }
21070
21071    /// Hooks that decline (`None`) must fall through to the configured policy
21072    /// even when the coordinate carries a [`semir`] `Hook` node, matching the
21073    /// legacy table path. Regression for the `unwrap_or(false)` that silently
21074    /// rejected declined hook nodes and bypassed [`UnknownSemanticPolicy`].
21075    fn hook_predicate_semantics() -> ParserSemantics {
21076        let mut ir = SemIr::new();
21077        let expr = ir.expr(PExpr::Hook(HookId::new(0)));
21078        ParserSemantics {
21079            ir,
21080            predicates: vec![ParserSemanticPredicate {
21081                rule_index: 0,
21082                pred_index: 0,
21083                expr,
21084                failure_message: None,
21085            }],
21086            actions: Vec::new(),
21087        }
21088    }
21089
21090    #[derive(Debug, Default)]
21091    struct DecliningHooks;
21092
21093    impl SemanticHooks for DecliningHooks {}
21094
21095    #[test]
21096    fn semir_hook_none_falls_through_to_assume_true() {
21097        let atn = predicate_after_token_atn();
21098        let semantics = hook_predicate_semantics();
21099        let mut parser = mini_parser_with_hooks(
21100            vec![
21101                TestToken::new(1).with_text("x"),
21102                TestToken::new(2).with_text("y"),
21103                TestToken::eof("parser-test", 2, 1, 2),
21104            ],
21105            DecliningHooks,
21106        );
21107
21108        let (tree, _) = parser
21109            .parse_atn_rule_with_runtime_options(
21110                &atn,
21111                0,
21112                ParserRuntimeOptions {
21113                    semantics: Some(&semantics),
21114                    unknown_predicate_policy: UnknownSemanticPolicy::AssumeTrue,
21115                    ..ParserRuntimeOptions::default()
21116                },
21117            )
21118            .expect("a declined SemIR hook must pass under assume-true");
21119
21120        assert_eq!(parser.node(tree).text(), "xy");
21121    }
21122
21123    #[test]
21124    fn semir_hook_none_falls_through_to_assume_false() {
21125        let atn = predicate_after_token_atn();
21126        let semantics = hook_predicate_semantics();
21127        let mut parser = mini_parser_with_hooks(
21128            vec![
21129                TestToken::new(1).with_text("x"),
21130                TestToken::new(2).with_text("y"),
21131                TestToken::eof("parser-test", 2, 1, 2),
21132            ],
21133            DecliningHooks,
21134        );
21135
21136        let result = parser.parse_atn_rule_with_runtime_options(
21137            &atn,
21138            0,
21139            ParserRuntimeOptions {
21140                semantics: Some(&semantics),
21141                unknown_predicate_policy: UnknownSemanticPolicy::AssumeFalse,
21142                ..ParserRuntimeOptions::default()
21143            },
21144        );
21145
21146        assert!(
21147            result.is_err(),
21148            "a declined SemIR hook must fail the only guarded path under assume-false"
21149        );
21150    }
21151
21152    #[test]
21153    fn semir_hook_none_records_coordinate_under_error_policy() {
21154        let atn = predicate_after_token_atn();
21155        let semantics = hook_predicate_semantics();
21156        let mut parser = mini_parser_with_hooks(
21157            vec![
21158                TestToken::new(1).with_text("x"),
21159                TestToken::new(2).with_text("y"),
21160                TestToken::eof("parser-test", 2, 1, 2),
21161            ],
21162            DecliningHooks,
21163        );
21164
21165        let error = parser
21166            .parse_atn_rule_with_runtime_options(
21167                &atn,
21168                0,
21169                ParserRuntimeOptions {
21170                    semantics: Some(&semantics),
21171                    unknown_predicate_policy: UnknownSemanticPolicy::Error,
21172                    ..ParserRuntimeOptions::default()
21173                },
21174            )
21175            .expect_err("a declined SemIR hook under Error policy must fail the parse");
21176
21177        let AntlrError::Unsupported(message) = error else {
21178            panic!("expected AntlrError::Unsupported, got {error:?}");
21179        };
21180        assert!(
21181            message.contains("unsupported semantic predicate") && message.contains("pred_index=0"),
21182            "message should name the unresolved coordinate: {message}"
21183        );
21184    }
21185
21186    #[test]
21187    fn generated_direct_predicate_honors_installed_policy() {
21188        // The generated recursive-descent path calls
21189        // `parser_semantic_ir_predicate_matches_with_context_and_local` without
21190        // going through `ParserRuntimeOptions`, so the policy must be installed
21191        // via `set_unknown_predicate_policy` (as the generated constructor now
21192        // does). A declining hook must then honor it rather than the default.
21193        let semantics = hook_predicate_semantics();
21194        let context = ParserRuleContext::new(0, -1);
21195
21196        let mut assume_true =
21197            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21198        assert!(
21199            assume_true.parser_semantic_ir_predicate_matches_with_context_and_local(
21200                &semantics, 0, 0, &context, 0
21201            ),
21202            "default AssumeTrue accepts a declined hook"
21203        );
21204        assert!(assume_true.take_unknown_semantic_error().is_none());
21205
21206        let mut error_policy =
21207            mini_parser_with_hooks(vec![TestToken::eof("t", 0, 1, 0)], DecliningHooks);
21208        error_policy.set_unknown_predicate_policy(UnknownSemanticPolicy::Error);
21209        assert!(
21210            !error_policy.parser_semantic_ir_predicate_matches_with_context_and_local(
21211                &semantics, 0, 0, &context, 0
21212            ),
21213            "Error policy rejects a declined hook on the generated-direct path"
21214        );
21215        let error = error_policy
21216            .take_unknown_semantic_error()
21217            .expect("Error policy records the unresolved coordinate for the generated path");
21218        let AntlrError::Unsupported(message) = error else {
21219            panic!("expected AntlrError::Unsupported, got {error:?}");
21220        };
21221        assert!(message.contains("pred_index=0"), "message: {message}");
21222    }
21223
21224    #[test]
21225    fn parser_rule_start_skips_leading_hidden_tokens() {
21226        let atn = token_then_eof_atn();
21227        let mut parser = mini_parser(vec![
21228            TestToken::new(99)
21229                .with_text(" ")
21230                .with_channel(HIDDEN_CHANNEL),
21231            TestToken::new(1).with_text("x"),
21232            TestToken::eof("parser-test", 2, 1, 2),
21233        ]);
21234
21235        let tree = parser
21236            .parse_atn_rule(&atn, 0)
21237            .expect("artificial parser rule should parse");
21238        let Some(rule) = parser.node(tree).first_rule(0).and_then(Node::as_rule) else {
21239            panic!("rule node should be present");
21240        };
21241        assert_eq!(
21242            rule.start()
21243                .expect("rule should have a start token")
21244                .token_type(),
21245            1
21246        );
21247    }
21248
21249    #[test]
21250    fn parser_action_after_eof_stops_at_eof_token() {
21251        let atn = eof_then_action_atn();
21252        let mut parser = mini_parser(vec![TestToken::eof("parser-test", 0, 1, 0)]);
21253
21254        let (_, actions) = parser
21255            .parse_atn_rule_with_runtime_options(&atn, 0, ParserRuntimeOptions::default())
21256            .expect("EOF action rule should parse");
21257
21258        assert_eq!(actions.len(), 1);
21259        assert_eq!(actions[0].stop_index(), Some(0));
21260        assert_eq!(
21261            parser.text_interval(actions[0].start_index(), actions[0].stop_index()),
21262            ""
21263        );
21264    }
21265
21266    #[test]
21267    fn after_action_stop_uses_rule_context_stop_not_cursor() {
21268        // A rule that ends right before EOF without matching it (e.g. `a: ID;`
21269        // called from `start: a EOF;`): after matching ID the cursor parks on EOF,
21270        // but the rule did not consume it. The @after stop must follow the rule
21271        // context's recorded stop (ID at index 0), not the cursor's EOF (index 1).
21272        let mut id = TestToken::new(1).with_text("x");
21273        id.set_token_index(0);
21274        let mut eof = TestToken::eof("parser-test", 1, 1, 1);
21275        eof.set_token_index(1);
21276        let mut parser = mini_parser(vec![id.clone(), eof]);
21277        // Advance the cursor onto EOF, as it would be after `a` matched ID.
21278        parser.consume();
21279        assert_eq!(parser.la(1), TOKEN_EOF);
21280
21281        // Rule `a` matched only ID, so its context stop is the ID token (index 0),
21282        // exactly what finish_rule(consumed_eof = false) records.
21283        let mut ctx = ParserRuleContext::new(0, 0);
21284        parser.set_context_stop(
21285            &mut ctx,
21286            parser.token_id_at(0).expect("ID token should be buffered"),
21287        );
21288        let tree = parser.rule_node(ctx);
21289
21290        let current_index = parser.input.index();
21291        // Cursor-only inference would wrongly pick EOF (the parked cursor)...
21292        assert_eq!(parser.after_action_stop_index(current_index), Some(1));
21293        // ...but the tree-aware helper follows the rule context stop (ID).
21294        assert_eq!(
21295            parser.after_action_stop_index_for_tree(tree, current_index),
21296            Some(0)
21297        );
21298    }
21299
21300    #[test]
21301    fn after_action_start_uses_rule_context_start_not_cursor() {
21302        // A rule that begins after leading hidden-channel tokens: the rule context
21303        // start (set by `enter_rule`) is the first visible token, not the raw cursor
21304        // that may still point at the hidden prefix. The @after start must follow
21305        // the context start so `$start`/`$text` excludes the hidden prefix.
21306        let mut parser = mini_parser(vec![
21307            TestToken::new(9)
21308                .with_text(" ")
21309                .with_channel(HIDDEN_CHANNEL),
21310            TestToken::new(9)
21311                .with_text(" ")
21312                .with_channel(HIDDEN_CHANNEL),
21313            TestToken::new(1).with_text("x"),
21314            TestToken::eof("parser-test", 3, 1, 3),
21315        ]);
21316
21317        let mut ctx = ParserRuleContext::new(0, 0);
21318        parser.set_context_start(
21319            &mut ctx,
21320            parser.token_id_at(2).expect("ID token should be buffered"),
21321        );
21322        let tree = parser.rule_node(ctx);
21323
21324        // The raw fallback (pre-rule cursor) would be 0 (the hidden prefix)...
21325        // ...but the tree-aware helper follows the rule context start (index 2).
21326        assert_eq!(parser.after_action_start_index_for_tree(tree, 0), 2);
21327
21328        // With no rule start recorded, it falls back to the provided index.
21329        let empty = parser.rule_node(ParserRuleContext::new(0, 0));
21330        assert_eq!(parser.after_action_start_index_for_tree(empty, 7), 7);
21331    }
21332
21333    fn clean_fast_outcome(index: usize, consumed_eof: bool, marker: u32) -> FastRecognizeOutcome {
21334        FastRecognizeOutcome {
21335            index,
21336            consumed_eof,
21337            diagnostics: DiagnosticSeqId::EMPTY,
21338            deferred_nodes: FastDeferredNodeId::EMPTY,
21339            nodes: NodeSeqId(marker),
21340        }
21341    }
21342
21343    #[test]
21344    fn clean_fast_outcome_dedupe_scans_small_lists_inline() {
21345        let mut outcomes = vec![
21346            clean_fast_outcome(4, false, 0),
21347            clean_fast_outcome(2, false, 1),
21348            clean_fast_outcome(4, false, 2),
21349            clean_fast_outcome(4, true, 3),
21350            clean_fast_outcome(2, false, 4),
21351        ];
21352        let mut scratch = FastOutcomeDedupScratch::default();
21353
21354        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21355
21356        assert_eq!(strategy, FastOutcomeDedupStrategy::Inline);
21357        assert_eq!(
21358            outcomes
21359                .iter()
21360                .map(|outcome| (outcome.index, outcome.consumed_eof, outcome.nodes.0))
21361                .collect::<Vec<_>>(),
21362            vec![(4, false, 0), (2, false, 1), (4, true, 3)]
21363        );
21364        assert!(scratch.dense_words.is_empty());
21365        assert!(scratch.sparse_keys.is_empty());
21366    }
21367
21368    #[test]
21369    fn clean_fast_outcome_dedupe_uses_and_reuses_dense_bitmap() {
21370        let mut scratch = FastOutcomeDedupScratch::default();
21371        let mut outcomes = (100..109)
21372            .flat_map(|index| {
21373                [
21374                    clean_fast_outcome(
21375                        index,
21376                        false,
21377                        u32::try_from(index).expect("test index fits in u32"),
21378                    ),
21379                    clean_fast_outcome(index, false, u32::MAX),
21380                ]
21381            })
21382            .collect();
21383
21384        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21385
21386        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21387        assert_eq!(outcomes.len(), 9);
21388        assert_eq!(outcomes[0].nodes, NodeSeqId(100));
21389        let dense_capacity = scratch.dense_words.capacity();
21390
21391        let mut reused = (1_000..1_009)
21392            .map(|index| {
21393                clean_fast_outcome(
21394                    index,
21395                    false,
21396                    u32::try_from(index).expect("test index fits in u32"),
21397                )
21398            })
21399            .collect();
21400        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21401
21402        assert_eq!(strategy, FastOutcomeDedupStrategy::Dense);
21403        assert_eq!(reused.len(), 9);
21404        assert_eq!(scratch.dense_words.capacity(), dense_capacity);
21405    }
21406
21407    #[test]
21408    fn clean_fast_outcome_dedupe_uses_and_reuses_sparse_hash() {
21409        let mut scratch = FastOutcomeDedupScratch::default();
21410        let sparse_indexes = [
21411            0, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000,
21412        ];
21413        let mut outcomes = sparse_indexes
21414            .into_iter()
21415            .chain([400_000])
21416            .enumerate()
21417            .map(|(marker, index)| {
21418                clean_fast_outcome(
21419                    index,
21420                    false,
21421                    u32::try_from(marker).expect("test marker fits in u32"),
21422                )
21423            })
21424            .collect();
21425
21426        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21427
21428        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21429        assert_eq!(outcomes.len(), sparse_indexes.len());
21430        assert_eq!(outcomes[4].nodes, NodeSeqId(4));
21431        let sparse_capacity = scratch.sparse_keys.capacity();
21432
21433        let mut reused = sparse_indexes
21434            .into_iter()
21435            .map(|index| {
21436                clean_fast_outcome(
21437                    index,
21438                    false,
21439                    u32::try_from(index).expect("test index fits in u32"),
21440                )
21441            })
21442            .collect();
21443        let strategy = dedupe_clean_fast_outcomes(&mut reused, &mut scratch);
21444
21445        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21446        assert_eq!(reused.len(), sparse_indexes.len());
21447        assert_eq!(scratch.sparse_keys.capacity(), sparse_capacity);
21448    }
21449
21450    #[test]
21451    fn clean_fast_outcome_dedupe_releases_oversized_sparse_hash() {
21452        let mut scratch = FastOutcomeDedupScratch::default();
21453        scratch
21454            .sparse_keys
21455            .reserve(MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS * 2);
21456        assert!(scratch.sparse_keys.capacity() > MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21457        let mut outcomes = (0..9)
21458            .map(|index| clean_fast_outcome(index * 100_000, false, index as u32))
21459            .collect();
21460
21461        let strategy = dedupe_clean_fast_outcomes(&mut outcomes, &mut scratch);
21462
21463        assert_eq!(strategy, FastOutcomeDedupStrategy::Sparse);
21464        assert!(scratch.sparse_keys.is_empty());
21465        assert!(scratch.sparse_keys.capacity() <= MAX_RETAINED_FAST_OUTCOME_SPARSE_KEYS);
21466    }
21467
21468    #[test]
21469    fn fast_outcome_selection_respects_sll_tie_order() {
21470        let mut arena = RecognitionArena::default();
21471        let first = FastRecognizeOutcome {
21472            index: 1,
21473            consumed_eof: false,
21474            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21475                line: 1,
21476                column: 0,
21477                message: "mismatched input 'x'".to_owned(),
21478                offending: None,
21479            }]),
21480            deferred_nodes: FastDeferredNodeId::EMPTY,
21481            nodes: NodeSeqId::EMPTY,
21482        };
21483        let second = FastRecognizeOutcome {
21484            index: first.index,
21485            consumed_eof: first.consumed_eof,
21486            diagnostics: DiagnosticSeqId::EMPTY,
21487            deferred_nodes: FastDeferredNodeId::EMPTY,
21488            nodes: NodeSeqId::EMPTY,
21489        };
21490
21491        let selected = select_best_fast_outcome(
21492            [first, second].into_iter(),
21493            PredictionMode::Sll,
21494            None,
21495            |_| panic!("caller-follow token probe should not run"),
21496            &arena,
21497        )
21498        .expect("one outcome should be selected");
21499        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
21500        let eof_second = FastRecognizeOutcome {
21501            index: second.index,
21502            consumed_eof: true,
21503            diagnostics: DiagnosticSeqId::EMPTY,
21504            deferred_nodes: FastDeferredNodeId::EMPTY,
21505            nodes: NodeSeqId::EMPTY,
21506        };
21507        let selected = select_best_fast_outcome(
21508            [first, eof_second].into_iter(),
21509            PredictionMode::Sll,
21510            None,
21511            |_| panic!("caller-follow token probe should not run"),
21512            &arena,
21513        )
21514        .expect("one outcome should be selected");
21515        assert!(!selected.consumed_eof);
21516        let selected = select_best_fast_outcome(
21517            [first, second].into_iter(),
21518            PredictionMode::Ll,
21519            None,
21520            |_| panic!("caller-follow token probe should not run"),
21521            &arena,
21522        )
21523        .expect("one outcome should be selected");
21524        assert!(selected.diagnostics.is_empty());
21525    }
21526
21527    #[test]
21528    fn recovery_fast_outcome_dedupe_uses_selection_rank() {
21529        let mut arena = RecognitionArena::default();
21530        let first = FastRecognizeOutcome {
21531            index: 3,
21532            consumed_eof: false,
21533            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21534                line: 1,
21535                column: 0,
21536                message: "mismatched input 'x' expecting 'a'".to_owned(),
21537                offending: None,
21538            }]),
21539            deferred_nodes: FastDeferredNodeId::EMPTY,
21540            nodes: NodeSeqId::EMPTY,
21541        };
21542        let same_rank = FastRecognizeOutcome {
21543            index: first.index,
21544            consumed_eof: first.consumed_eof,
21545            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21546                line: 1,
21547                column: 0,
21548                message: "mismatched input 'x' expecting 'b'".to_owned(),
21549                offending: None,
21550            }]),
21551            deferred_nodes: FastDeferredNodeId::EMPTY,
21552            nodes: NodeSeqId::EMPTY,
21553        };
21554        let better_rank = FastRecognizeOutcome {
21555            index: first.index,
21556            consumed_eof: first.consumed_eof,
21557            diagnostics: arena.diagnostic_sequence([ParserDiagnostic {
21558                line: 1,
21559                column: 0,
21560                message: "missing 'a' at 'x'".to_owned(),
21561                offending: None,
21562            }]),
21563            deferred_nodes: FastDeferredNodeId::EMPTY,
21564            nodes: NodeSeqId::EMPTY,
21565        };
21566        let mut outcomes = vec![first, same_rank, better_rank];
21567
21568        dedupe_fast_outcomes(&mut outcomes, &arena);
21569
21570        assert_eq!(outcomes.len(), 2);
21571        assert_eq!(
21572            arena
21573                .diagnostics(outcomes[0].diagnostics)
21574                .next()
21575                .expect("first diagnostic")
21576                .message,
21577            "mismatched input 'x' expecting 'a'"
21578        );
21579        assert_eq!(
21580            arena
21581                .diagnostics(outcomes[1].diagnostics)
21582                .next()
21583                .expect("second diagnostic")
21584                .message,
21585            "missing 'a' at 'x'"
21586        );
21587    }
21588
21589    #[test]
21590    fn fast_outcome_selection_prefers_generated_caller_follow() {
21591        let arena = RecognitionArena::default();
21592        let earlier = FastRecognizeOutcome {
21593            index: 7,
21594            consumed_eof: false,
21595            diagnostics: DiagnosticSeqId::EMPTY,
21596            deferred_nodes: FastDeferredNodeId::EMPTY,
21597            nodes: NodeSeqId::EMPTY,
21598        };
21599        let later = FastRecognizeOutcome {
21600            index: 8,
21601            consumed_eof: false,
21602            diagnostics: DiagnosticSeqId::EMPTY,
21603            deferred_nodes: FastDeferredNodeId::EMPTY,
21604            nodes: NodeSeqId::EMPTY,
21605        };
21606        let mut follow = TokenBitSet::default();
21607        follow.insert(5);
21608
21609        let selected = select_best_fast_outcome(
21610            [later, earlier].into_iter(),
21611            PredictionMode::Ll,
21612            Some(&follow),
21613            |index| (if index == 7 { 5 } else { TOKEN_EOF }, index == 7, true),
21614            &arena,
21615        )
21616        .expect("one outcome should be selected");
21617        assert_eq!(selected.index, 7);
21618
21619        let selected = select_best_fast_outcome(
21620            [later, earlier].into_iter(),
21621            PredictionMode::Ll,
21622            Some(&follow),
21623            |index| (if index == 7 { 5 } else { TOKEN_EOF }, false, true),
21624            &arena,
21625        )
21626        .expect("one outcome should be selected");
21627        assert_eq!(selected.index, 8);
21628
21629        let indented_next_statement = FastRecognizeOutcome {
21630            index: 9,
21631            consumed_eof: false,
21632            diagnostics: DiagnosticSeqId::EMPTY,
21633            deferred_nodes: FastDeferredNodeId::EMPTY,
21634            nodes: NodeSeqId::EMPTY,
21635        };
21636        let selected = select_best_fast_outcome(
21637            [indented_next_statement, earlier].into_iter(),
21638            PredictionMode::Ll,
21639            Some(&follow),
21640            |index| {
21641                let is_boundary = index == 7;
21642                let is_boundary_gap = matches!(index, 7 | 8);
21643                (
21644                    if index == 7 { 5 } else { TOKEN_EOF },
21645                    is_boundary,
21646                    is_boundary_gap,
21647                )
21648            },
21649            &arena,
21650        )
21651        .expect("one outcome should be selected");
21652        assert_eq!(selected.index, 7);
21653
21654        let continuation = FastRecognizeOutcome {
21655            index: 10,
21656            consumed_eof: false,
21657            diagnostics: DiagnosticSeqId::EMPTY,
21658            deferred_nodes: FastDeferredNodeId::EMPTY,
21659            nodes: NodeSeqId::EMPTY,
21660        };
21661        let selected = select_best_fast_outcome(
21662            [continuation, earlier].into_iter(),
21663            PredictionMode::Ll,
21664            Some(&follow),
21665            |index| {
21666                let is_boundary = matches!(index, 7 | 9);
21667                (
21668                    if index == 7 { 5 } else { TOKEN_EOF },
21669                    is_boundary,
21670                    is_boundary,
21671                )
21672            },
21673            &arena,
21674        )
21675        .expect("one outcome should be selected");
21676        assert_eq!(selected.index, 10);
21677
21678        let selected = select_best_fast_outcome(
21679            [earlier, later].into_iter(),
21680            PredictionMode::Sll,
21681            Some(&follow),
21682            |_| panic!("caller-follow token probe should not run in SLL mode"),
21683            &arena,
21684        )
21685        .expect("one outcome should be selected");
21686        assert_eq!(selected.index, 8);
21687    }
21688
21689    #[test]
21690    fn caller_follow_boundary_text_requires_separator_shape() {
21691        assert!(is_caller_follow_boundary_text(";"));
21692        assert!(is_caller_follow_boundary_text("\n"));
21693        assert!(is_caller_follow_boundary_text("\r\n  "));
21694        assert!(is_caller_follow_boundary_text(";\n"));
21695        assert!(!is_caller_follow_boundary_text("\"\"\"line1\nline2\"\"\""));
21696        assert!(!is_caller_follow_boundary_text("/* line1\nline2 */"));
21697        assert!(!is_caller_follow_boundary_text("identifier"));
21698        assert!(is_caller_follow_boundary_gap_text(" \t "));
21699        assert!(is_caller_follow_boundary_gap_text("\n  "));
21700        assert!(is_caller_follow_boundary_gap_text(";\t"));
21701        assert!(!is_caller_follow_boundary_gap_text(
21702            "\"\"\"line1\nline2\"\"\""
21703        ));
21704        assert!(!is_caller_follow_boundary_gap_text("/* line1\nline2 */"));
21705    }
21706
21707    #[test]
21708    fn caller_follow_token_info_treats_hidden_tokens_as_boundary_gaps() {
21709        let mut parser = mini_parser(vec![
21710            TestToken::new(5).with_text("\n"),
21711            TestToken::new(6)
21712                .with_text("// comment\n")
21713                .with_channel(HIDDEN_CHANNEL),
21714            TestToken::new(1).with_text("x"),
21715            TestToken::eof("parser-test", 1, 2, 0),
21716        ]);
21717
21718        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
21719        assert_eq!(parser.caller_follow_token_info(1), (6, false, true));
21720        assert_eq!(parser.caller_follow_token_info(2), (1, false, false));
21721    }
21722
21723    #[test]
21724    fn caller_follow_token_info_uses_stream_visible_channel() {
21725        let source = Source {
21726            tokens: vec![
21727                TestToken::new(5).with_text("\n").with_channel(2),
21728                TestToken::new(1).with_text("x").with_channel(2),
21729                TestToken::new(6)
21730                    .with_text("// comment\n")
21731                    .with_channel(HIDDEN_CHANNEL),
21732                TestToken::eof("parser-test", 1, 2, 0),
21733            ],
21734            index: 0,
21735        };
21736        let data = RecognizerData::new(
21737            "Mini.g4",
21738            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21739        );
21740        let mut parser = BaseParser::new(CommonTokenStream::with_channel(source, 2), data);
21741
21742        assert_eq!(parser.caller_follow_token_info(0), (5, true, true));
21743        assert_eq!(parser.caller_follow_token_info(1), (1, false, false));
21744        assert_eq!(parser.caller_follow_token_info(2), (6, false, true));
21745    }
21746
21747    #[test]
21748    fn reset_per_parse_caches_clears_state_expected_token_cache() {
21749        let atn = token_then_eof_atn();
21750        let mut parser = mini_parser(Vec::new());
21751
21752        let _ = parser.cached_state_expected_token_set(&atn, 0);
21753        assert!(!parser.state_expected_token_cache.is_empty());
21754
21755        parser.reset_per_parse_caches();
21756        assert!(parser.state_expected_token_cache.is_empty());
21757    }
21758
21759    #[test]
21760    fn empty_cycle_cache_survives_reset_and_invalidates_for_a_different_atn() {
21761        let cyclic = epsilon_cycle_atn();
21762        let acyclic = token_then_eof_atn();
21763        let mut parser = mini_parser(Vec::new());
21764
21765        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
21766        assert_eq!(
21767            parser.empty_cycle_cache_atn,
21768            Some(SharedAtnCacheKey::for_atn(&cyclic))
21769        );
21770        assert_eq!(parser.empty_cycle_cache[1], Some(true));
21771
21772        parser.reset_per_parse_caches();
21773        assert_eq!(parser.empty_cycle_cache[1], Some(true));
21774        assert!(parser.state_can_reenter_without_consuming(&cyclic, 1));
21775
21776        assert!(!parser.state_can_reenter_without_consuming(&acyclic, 1));
21777        assert_eq!(
21778            parser.empty_cycle_cache_atn,
21779            Some(SharedAtnCacheKey::for_atn(&acyclic))
21780        );
21781        assert_eq!(parser.empty_cycle_cache[1], Some(false));
21782    }
21783
21784    #[test]
21785    fn parser_error_with_empty_expected_set_omits_empty_set_display() {
21786        let source = Source {
21787            tokens: vec![
21788                TestToken::new(1).with_text("x"),
21789                TestToken::eof("parser-test", 1, 1, 1),
21790            ],
21791            index: 0,
21792        };
21793        let data = RecognizerData::new(
21794            "Mini.g4",
21795            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21796        );
21797        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
21798        let expected = ExpectedTokens {
21799            index: Some(0),
21800            symbols: BTreeSet::new(),
21801            no_viable: None,
21802        };
21803
21804        let (_, message) = parser.expected_error_message(0, 0, &expected);
21805
21806        assert_eq!(message, "mismatched input 'x'");
21807    }
21808
21809    #[test]
21810    fn eof_rule_stop_index_points_at_eof_token() {
21811        let source = Source {
21812            tokens: vec![
21813                TestToken::new(1).with_text("x"),
21814                TestToken::eof("parser-test", 1, 1, 1),
21815            ],
21816            index: 0,
21817        };
21818        let data = RecognizerData::new(
21819            "Mini.g4",
21820            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
21821        );
21822        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
21823
21824        assert_eq!(parser.rule_stop_token_index(1, true), Some(1));
21825        assert_eq!(parser.rule_stop_token_index(1, false), Some(0));
21826    }
21827
21828    #[test]
21829    fn generated_parser_action_uses_current_rule_stop_boundary() {
21830        let mut parser = mini_parser(vec![
21831            TestToken::new(1).with_text("x"),
21832            TestToken::eof("parser-test", 1, 1, 1),
21833        ]);
21834
21835        parser.match_token(1).expect("token should match");
21836        let action = parser.parser_action_at_current(7, 0, 0, false);
21837        assert_eq!(action.source_state(), 7);
21838        assert_eq!(action.rule_index(), 0);
21839        assert_eq!(action.start_index(), 0);
21840        assert_eq!(action.stop_index(), Some(0));
21841
21842        parser.match_eof().expect("EOF should match");
21843        let action = parser.parser_action_at_current(8, 0, 0, true);
21844        assert_eq!(action.stop_index(), Some(1));
21845    }
21846
21847    #[test]
21848    fn folds_left_recursive_boundary_into_rule_node() {
21849        let mut arena = RecognitionArena::default();
21850        let first = arena.push_node(ArenaRecognizedNode::Token {
21851            token: TokenId::try_from(0).expect("test token ID"),
21852        });
21853        let boundary = arena.push_node(ArenaRecognizedNode::LeftRecursiveBoundary {
21854            rule_index: 1,
21855            alt_number: 3,
21856        });
21857        let second = arena.push_node(ArenaRecognizedNode::Token {
21858            token: TokenId::try_from(1).expect("test token ID"),
21859        });
21860        let mut nodes = NodeSeqId::EMPTY;
21861        for node in [first, boundary, second].into_iter().rev() {
21862            nodes = arena.prepend(nodes, node);
21863        }
21864
21865        let folded = arena.fold_left_recursive_boundaries(nodes);
21866        let folded_nodes = arena.iter(folded).collect::<Vec<_>>();
21867
21868        assert_eq!(folded_nodes.len(), 2);
21869        let ArenaRecognizedNode::Rule {
21870            rule_index,
21871            invoking_state,
21872            alt_number,
21873            start_index,
21874            stop_index,
21875            children,
21876            ..
21877        } = arena.node(folded_nodes[0])
21878        else {
21879            panic!("first folded node should be a rule");
21880        };
21881        // The folded rule node's scalar shape (rule/invoking-state/alt/start/stop) is one snapshot;
21882        // child resolution and the sibling identity below stay explicit — a node Debug prints the
21883        // children handle, not the resolved sequence they assert on.
21884        insta::assert_debug_snapshot!(
21885            "folds_left_recursive_boundary_into_rule_node",
21886            (
21887                rule_index,
21888                invoking_state,
21889                alt_number,
21890                start_index,
21891                stop_index
21892            )
21893        );
21894        assert_eq!(arena.iter(children).collect::<Vec<_>>(), [first]);
21895        assert_eq!(arena.node(folded_nodes[1]), arena.node(second));
21896
21897        let stats = arena.stats(folded, DiagnosticSeqId::EMPTY);
21898        assert_eq!(
21899            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
21900            (4, 3, 1)
21901        );
21902        assert_eq!(
21903            (stats.total_links, stats.live_links, stats.dead_links),
21904            (9, 3, 6)
21905        );
21906    }
21907
21908    #[test]
21909    fn recognition_arena_reports_live_dead_and_retained_capacity() {
21910        let mut arena = RecognitionArena::default();
21911        let token = arena.push_node(ArenaRecognizedNode::Token {
21912            token: TokenId::try_from(0).expect("test token ID"),
21913        });
21914        let extra = arena.push_extra(RecognitionExtra::MissingToken {
21915            token_type: 2,
21916            at_index: 1,
21917            text: "<missing X>".to_owned(),
21918        });
21919        let missing = arena.push_node(ArenaRecognizedNode::MissingToken { extra });
21920        let discarded = arena.push_node(ArenaRecognizedNode::ErrorToken {
21921            token: TokenId::try_from(1).expect("test token ID"),
21922        });
21923        let mut live = NodeSeqId::EMPTY;
21924        live = arena.prepend(live, missing);
21925        live = arena.prepend(live, token);
21926        let _discarded_sequence = arena.prepend(NodeSeqId::EMPTY, discarded);
21927        let live_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
21928            line: 1,
21929            column: 0,
21930            message: "missing X".to_owned(),
21931            offending: None,
21932        }]);
21933        let _discarded_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
21934            line: 1,
21935            column: 1,
21936            message: "discarded".to_owned(),
21937            offending: None,
21938        }]);
21939        let deferred_children = arena.deferred_fragment(live);
21940        let _deferred_rule = arena.deferred_rule_node(FastDeferredRule {
21941            rule_index: 0,
21942            invoking_state: -1,
21943            start_index: 0,
21944            stop_index: Some(1),
21945            deferred_children,
21946            children: NodeSeqId::EMPTY,
21947        });
21948
21949        let stats = arena.stats(live, live_diagnostics);
21950
21951        assert_eq!(
21952            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
21953            (3, 2, 1)
21954        );
21955        assert_eq!(
21956            (stats.total_links, stats.live_links, stats.dead_links),
21957            (5, 3, 2)
21958        );
21959        assert_eq!(
21960            (stats.total_extras, stats.live_extras, stats.dead_extras),
21961            (3, 2, 1)
21962        );
21963        assert!(size_of::<SeqLink>() <= 8);
21964        assert!(size_of::<DiagnosticLink>() <= 8);
21965        assert!(size_of::<FastDeferredNode>() <= 12);
21966        assert!(size_of::<FastDeferredRule>() <= 28);
21967        assert!(size_of::<FastRecognizeOutcome>() <= 24);
21968        let capacities = (
21969            stats.node_capacity,
21970            stats.link_capacity,
21971            stats.extra_capacity,
21972        );
21973        let deferred_capacities = (
21974            arena.deferred_nodes.capacity(),
21975            arena.deferred_rules.capacity(),
21976        );
21977
21978        arena.reset();
21979        let reset = arena.stats(NodeSeqId::EMPTY, DiagnosticSeqId::EMPTY);
21980        assert_eq!(
21981            (reset.total_nodes, reset.total_links, reset.total_extras),
21982            (0, 0, 0)
21983        );
21984        assert_eq!(
21985            (
21986                reset.node_capacity,
21987                reset.link_capacity,
21988                reset.extra_capacity,
21989            ),
21990            capacities
21991        );
21992        assert!(arena.deferred_nodes.is_empty());
21993        assert!(arena.deferred_rules.is_empty());
21994        assert_eq!(
21995            (
21996                arena.deferred_nodes.capacity(),
21997                arena.deferred_rules.capacity(),
21998            ),
21999            deferred_capacities
22000        );
22001    }
22002
22003    #[test]
22004    fn parser_computes_recognition_arena_stats_on_demand() {
22005        let mut parser = mini_parser(Vec::new());
22006        let live = parser
22007            .recognition_arena
22008            .push_node(ArenaRecognizedNode::Token {
22009                token: TokenId::try_from(0).expect("test token ID"),
22010            });
22011        let discarded = parser
22012            .recognition_arena
22013            .push_node(ArenaRecognizedNode::ErrorToken {
22014                token: TokenId::try_from(1).expect("test token ID"),
22015            });
22016        let live_root = parser.recognition_arena.prepend(NodeSeqId::EMPTY, live);
22017        let _discarded_root = parser
22018            .recognition_arena
22019            .prepend(NodeSeqId::EMPTY, discarded);
22020        parser.finish_recognition_arena(live_root, DiagnosticSeqId::EMPTY);
22021
22022        let stats = parser.recognition_arena_stats();
22023
22024        assert_eq!(
22025            (stats.total_nodes, stats.live_nodes, stats.dead_nodes),
22026            (2, 1, 1)
22027        );
22028        assert_eq!(
22029            (stats.total_links, stats.live_links, stats.dead_links),
22030            (2, 1, 1)
22031        );
22032    }
22033
22034    #[test]
22035    fn recognition_arena_drops_capacity_above_retention_limit() {
22036        let mut storage = Vec::<u8>::with_capacity(4);
22037        storage.extend([1, 2, 3]);
22038
22039        reset_arena_vec(&mut storage, 3);
22040
22041        assert!(storage.is_empty());
22042        assert_eq!(storage.capacity(), 0);
22043    }
22044
22045    #[test]
22046    fn recognition_arena_concatenates_diagnostics_in_source_order() {
22047        let mut arena = RecognitionArena::default();
22048        let prefix = arena.diagnostic_sequence([
22049            ParserDiagnostic {
22050                line: 1,
22051                column: 0,
22052                message: "first".to_owned(),
22053                offending: None,
22054            },
22055            ParserDiagnostic {
22056                line: 1,
22057                column: 1,
22058                message: "second".to_owned(),
22059                offending: None,
22060            },
22061        ]);
22062        let suffix = arena.diagnostic_sequence([ParserDiagnostic {
22063            line: 1,
22064            column: 2,
22065            message: "third".to_owned(),
22066            offending: None,
22067        }]);
22068        let extras_before = arena.extras.len();
22069
22070        let combined = arena.concat_diagnostics(prefix, suffix);
22071        let messages = arena
22072            .diagnostics(combined)
22073            .map(|diagnostic| diagnostic.message.as_str())
22074            .collect::<Vec<_>>();
22075
22076        assert_eq!(messages, ["first", "second", "third"]);
22077        assert_eq!(arena.extras.len(), extras_before);
22078    }
22079
22080    #[test]
22081    fn outcome_ties_keep_later_non_recursive_alternative() {
22082        let arena = RecognitionArena::default();
22083        let first = RecognizeOutcome {
22084            index: 1,
22085            consumed_eof: false,
22086            alt_number: 0,
22087            member_values: MemberEnv::new(),
22088            return_values: BTreeMap::new(),
22089            diagnostics: DiagnosticSeqId::EMPTY,
22090            decisions: Vec::new(),
22091            actions: vec![ParserAction::new(1, 0, 0, None)],
22092            nodes: NodeSeqId::EMPTY,
22093        };
22094        let second = RecognizeOutcome {
22095            actions: vec![ParserAction::new(2, 0, 0, None)],
22096            ..first.clone()
22097        };
22098
22099        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22100            .expect("one outcome should be selected");
22101        assert_eq!(selected.actions[0].source_state(), 2);
22102    }
22103
22104    #[test]
22105    fn outcome_ties_prefer_more_actions_for_non_recursive_paths() {
22106        let arena = RecognitionArena::default();
22107        let first = RecognizeOutcome {
22108            index: 1,
22109            consumed_eof: false,
22110            alt_number: 0,
22111            member_values: MemberEnv::new(),
22112            return_values: BTreeMap::new(),
22113            diagnostics: DiagnosticSeqId::EMPTY,
22114            decisions: Vec::new(),
22115            actions: vec![ParserAction::new(1, 0, 0, None)],
22116            nodes: NodeSeqId::EMPTY,
22117        };
22118        let second = RecognizeOutcome {
22119            actions: vec![
22120                ParserAction::new(2, 0, 0, None),
22121                ParserAction::new(3, 0, 0, None),
22122            ],
22123            ..first.clone()
22124        };
22125
22126        let selected = select_best_outcome([second, first].into_iter(), PredictionMode::Ll, &arena)
22127            .expect("one outcome should be selected");
22128        assert_eq!(selected.actions.len(), 2);
22129    }
22130
22131    #[test]
22132    fn outcome_ties_prefer_later_action_stop_for_greedy_optional_paths() {
22133        let arena = RecognitionArena::default();
22134        let first = RecognizeOutcome {
22135            index: 7,
22136            consumed_eof: false,
22137            alt_number: 0,
22138            member_values: MemberEnv::new(),
22139            return_values: BTreeMap::new(),
22140            diagnostics: DiagnosticSeqId::EMPTY,
22141            decisions: vec![1, 0],
22142            actions: vec![
22143                ParserAction::new(23, 2, 2, Some(4)),
22144                ParserAction::new(23, 2, 0, Some(6)),
22145            ],
22146            nodes: NodeSeqId::EMPTY,
22147        };
22148        let second = RecognizeOutcome {
22149            decisions: vec![0, 1],
22150            actions: vec![
22151                ParserAction::new(23, 2, 2, Some(6)),
22152                ParserAction::new(23, 2, 0, Some(6)),
22153            ],
22154            ..first.clone()
22155        };
22156
22157        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22158            .expect("one outcome should be selected");
22159        assert_eq!(selected.actions[0].stop_index(), Some(6));
22160    }
22161
22162    #[test]
22163    fn outcome_ties_keep_first_recursive_tree_shape() {
22164        let mut arena = RecognitionArena::default();
22165        let token = arena.push_node(ArenaRecognizedNode::Token {
22166            token: TokenId::try_from(0).expect("test token ID"),
22167        });
22168        let token_children = arena.prepend(NodeSeqId::EMPTY, token);
22169        let inner = arena.push_node(ArenaRecognizedNode::Rule {
22170            rule_index: 1,
22171            invoking_state: -1,
22172            alt_number: 0,
22173            start_index: 0,
22174            stop_index: Some(0),
22175            return_values: None,
22176            children: token_children,
22177        });
22178        let inner_children = arena.prepend(NodeSeqId::EMPTY, inner);
22179        let outer = arena.push_node(ArenaRecognizedNode::Rule {
22180            rule_index: 1,
22181            invoking_state: -1,
22182            alt_number: 0,
22183            start_index: 0,
22184            stop_index: Some(0),
22185            return_values: None,
22186            children: inner_children,
22187        });
22188        let recursive_nodes = arena.prepend(NodeSeqId::EMPTY, outer);
22189        let first = RecognizeOutcome {
22190            index: 1,
22191            consumed_eof: false,
22192            alt_number: 0,
22193            member_values: MemberEnv::new(),
22194            return_values: BTreeMap::new(),
22195            diagnostics: DiagnosticSeqId::EMPTY,
22196            decisions: Vec::new(),
22197            actions: vec![ParserAction::new(1, 0, 0, None)],
22198            nodes: recursive_nodes,
22199        };
22200        let second = RecognizeOutcome {
22201            index: 1,
22202            consumed_eof: false,
22203            alt_number: 0,
22204            member_values: MemberEnv::new(),
22205            return_values: BTreeMap::new(),
22206            diagnostics: DiagnosticSeqId::EMPTY,
22207            decisions: Vec::new(),
22208            actions: vec![ParserAction::new(2, 0, 0, None)],
22209            nodes: recursive_nodes,
22210        };
22211
22212        let selected = select_best_outcome([first, second].into_iter(), PredictionMode::Ll, &arena)
22213            .expect("one outcome should be selected");
22214        assert_eq!(selected.actions[0].source_state(), 1);
22215    }
22216
22217    #[test]
22218    fn sll_outcome_selection_keeps_earlier_recovered_alt() {
22219        let mut arena = RecognitionArena::default();
22220        let recovered_diagnostics = arena.diagnostic_sequence([ParserDiagnostic {
22221            line: 1,
22222            column: 3,
22223            message: "missing 'Y' at '<EOF>'".to_owned(),
22224            offending: None,
22225        }]);
22226        let first_alt = RecognizeOutcome {
22227            index: 2,
22228            consumed_eof: true,
22229            alt_number: 0,
22230            member_values: MemberEnv::new(),
22231            return_values: BTreeMap::new(),
22232            diagnostics: recovered_diagnostics,
22233            decisions: vec![0],
22234            actions: vec![ParserAction::new(1, 0, 0, None)],
22235            nodes: NodeSeqId::EMPTY,
22236        };
22237        let second_alt = RecognizeOutcome {
22238            diagnostics: DiagnosticSeqId::EMPTY,
22239            decisions: vec![1],
22240            actions: vec![ParserAction::new(2, 0, 0, None)],
22241            ..first_alt.clone()
22242        };
22243
22244        let selected = select_best_outcome(
22245            [second_alt, first_alt].into_iter(),
22246            PredictionMode::Sll,
22247            &arena,
22248        )
22249        .expect("one outcome should be selected");
22250        assert_eq!(arena.diagnostics_len(selected.diagnostics), 1);
22251        assert_eq!(selected.decisions, [0]);
22252    }
22253}