Skip to main content

antlr4_runtime/atn/
parser.rs

1use crate::atn::AtnStateKind;
2use crate::atn::parser_atn::{
3    ParserAtn as Atn, ParserAtnState as AtnState, ParserTransition, ParserTransitionKind,
4};
5#[cfg(test)]
6use crate::atn::parser_atn::{ParserAtnBuilder, ParserTransitionSpec};
7use crate::dfa::{
8    DfaStateBuilder, DfaStateId, NO_DFA_STATE, ParserDfa, ParserDfaStateView, ParserDfaStats,
9};
10use crate::int_stream::IntStream;
11use crate::prediction::{
12    AtnConfig, AtnConfigSet, ContextArena, ContextId, EMPTY_CONTEXT, EMPTY_RETURN_STATE,
13    PredictionContextStats, PredictionFxHasher, PredictionWorkspace, SemanticContext,
14    all_subsets_conflict, all_subsets_equal, conflicting_alt_subsets,
15    has_sll_conflict_terminating_prediction, single_viable_alt,
16};
17use crate::token::TOKEN_EOF;
18use std::cell::RefCell;
19use std::collections::{HashMap, HashSet};
20use std::hash::BuildHasherDefault;
21
22type FxHashSet<T> = HashSet<T, BuildHasherDefault<PredictionFxHasher>>;
23
24#[derive(Debug)]
25pub struct ParserAtnSimulator<'a> {
26    atn: &'a Atn,
27    store: PredictionStore,
28    workspace: PredictionWorkspace,
29    outer_context_cache: Option<CachedOuterContext>,
30    outer_context_cache_hits: usize,
31    outer_context_cache_misses: usize,
32    /// Accept states treated as provisional by the latest direct prediction.
33    /// Generated SLL still uses their stored accept metadata.
34    deferred_accept_states: FxHashSet<(usize, DfaStateId)>,
35    shared_cache_key: Option<usize>,
36    shared_cache_generation: u64,
37    /// Java's `LL_EXACT_AMBIG_DETECTION`: the full-context loop keeps
38    /// consuming past "resolves to one viable alt" conflicts until every
39    /// `(state, context)` subset conflicts over the same alt set.
40    exact_ambig_detection: bool,
41    /// Memoized full-context resolutions. Upstream re-runs the LL simulation
42    /// on every visit to a `requires_full_context` DFA state; grammars with
43    /// keyword/identifier-style true ambiguities (Avro IDL's `nullableType`,
44    /// SQL non-reserved keywords) pay that on every occurrence. Under the
45    /// memo gate — no predicate transitions in the ATN — the LL result is a
46    /// pure function of the decision, precedence, interned caller context,
47    /// and the token window the loop read, so identical occurrences replay
48    /// the recorded resolution. The gate carries that purity claim: general
49    /// ANTLR full-context closure can also consult parser state through
50    /// `predTransition`, which is exactly what the gate excludes.
51    full_context_memo: HashMap<
52        FullContextMemoKey,
53        Vec<FullContextMemoEntry>,
54        BuildHasherDefault<PredictionFxHasher>,
55    >,
56    full_context_memo_len: usize,
57    /// Whether the memo is sound for this ATN: predicates make prediction
58    /// outcomes depend on caller-side evaluation, so any semantic transition
59    /// disables memoization entirely. Computed lazily on first retry.
60    full_context_memo_gate: Option<bool>,
61}
62
63#[derive(Clone, Copy, Debug)]
64struct CachedOuterContext {
65    rule_context_version: usize,
66    context: ContextId,
67}
68
69/// Lookup key for one memoized full-context resolution.
70///
71/// The first window token joins the key so a probe is one hash lookup in
72/// the common case (distinct keyword per resolution) instead of a scan.
73///
74/// `outer_context` is the interned FULL caller stack, which bounds the hit
75/// rate: the same construct at rule-nesting depth 3 and depth 4 has
76/// different `ContextId`s and misses. Flat-ish grammars (Avro IDL: ~155
77/// unique contexts against 2,100 retries) hit almost always; deeply
78/// recursive grammars re-derive once per distinct nesting shape.
79#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
80struct FullContextMemoKey {
81    decision: usize,
82    precedence: i32,
83    outer_context: ContextId,
84    first_symbol: i32,
85}
86
87/// One memoized full-context resolution.
88///
89/// `window_tail` is the visible-token sequence the recorded LL loop read
90/// after the keyed first symbol, so a hit replays only when the upcoming
91/// input matches token-for-token — identical decision + precedence +
92/// interned caller context + read window is literally the same computation.
93///
94/// `prediction.stop_index` holds the RECORDING run's absolute index and is
95/// stale for any other occurrence — the probe unconditionally overwrites it
96/// from the live cursor before returning a replay. Do not read it directly.
97#[derive(Clone, Debug)]
98struct FullContextMemoEntry {
99    window_tail: Vec<i32>,
100    prediction: FullContextPrediction,
101}
102
103/// Memoized windows above this many visible tokens are not recorded: long
104/// ambiguous prefixes are rare, and verifying a hit costs a token compare
105/// per window token.
106const FULL_CONTEXT_MEMO_MAX_WINDOW: usize = 16;
107/// Total memo entries per simulator. Contexts are interned per parse and
108/// real grammars produce a few hundred; the bound only guards adversarial
109/// context churn.
110const FULL_CONTEXT_MEMO_MAX_ENTRIES: usize = 4096;
111
112/// ATN-static memo gate, cached per thread by ATN identity.
113///
114/// The gate is a property of the ATN alone, but generated parsers build a
115/// simulator per parser instance, so a per-simulator cache would rescan the
116/// ATN on the first LL retry of every parse — pure cost for grammars the
117/// gate turns off. Keyed like `SHARED_PREDICTION_STORES`.
118fn atn_has_predicate_transition(atn: &Atn) -> bool {
119    thread_local! {
120        static GATES: RefCell<HashMap<usize, bool, BuildHasherDefault<PredictionFxHasher>>> =
121            RefCell::new(HashMap::default());
122    }
123    let ptr: *const Atn = atn;
124    let key = ptr as usize;
125    GATES.with(|gates| {
126        *gates.borrow_mut().entry(key).or_insert_with(|| {
127            (0..atn.state_count()).any(|state_number| {
128                atn.state(state_number).is_some_and(|state| {
129                    state
130                        .transitions()
131                        .into_iter()
132                        .any(|transition| transition.kind() == ParserTransitionKind::Predicate)
133                })
134            })
135        })
136    })
137}
138
139#[derive(Debug, Default)]
140struct PredictionStore {
141    contexts: ContextArena,
142    decision_to_dfa: Vec<ParserDfa>,
143}
144
145impl PredictionStore {
146    fn new(atn: &Atn) -> Self {
147        Self {
148            contexts: ContextArena::new(),
149            decision_to_dfa: initial_decision_dfas(atn),
150        }
151    }
152}
153
154#[derive(Debug, Default)]
155struct SharedPredictionStore {
156    generation: u64,
157    store: Option<PredictionStore>,
158}
159
160thread_local! {
161    static SHARED_PREDICTION_STORES: RefCell<HashMap<usize, SharedPredictionStore>> =
162        RefCell::new(HashMap::new());
163}
164
165fn clear_shared_prediction_store(key: usize) -> u64 {
166    SHARED_PREDICTION_STORES.with(|cache| {
167        let mut cache = cache.borrow_mut();
168        let shared = cache.entry(key).or_default();
169        shared.generation = shared.generation.wrapping_add(1);
170        shared.store = None;
171        shared.generation
172    })
173}
174
175#[derive(Clone, Debug, Eq, PartialEq)]
176pub struct ParserAtnPrediction {
177    pub alt: usize,
178    pub requires_full_context: bool,
179    pub has_semantic_context: bool,
180    pub diagnostic: Option<ParserAtnPredictionDiagnostic>,
181}
182
183#[derive(Clone, Debug, Eq, PartialEq)]
184pub struct ParserAtnPredictionDiagnostic {
185    pub kind: ParserAtnPredictionDiagnosticKind,
186    pub start_index: usize,
187    pub sll_stop_index: usize,
188    pub ll_stop_index: usize,
189    pub conflicting_alts: Vec<usize>,
190    /// For [`ParserAtnPredictionDiagnosticKind::Ambiguity`]: whether the
191    /// full-context loop proved an exact ambiguity (Java's `exact` flag —
192    /// the default `DiagnosticErrorListener` only reports exact ones).
193    pub exact: bool,
194}
195
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197pub enum ParserAtnPredictionDiagnosticKind {
198    Ambiguity,
199    ContextSensitivity,
200}
201
202#[derive(Clone, Copy)]
203struct PredictionCheck {
204    decision: usize,
205    decision_state: usize,
206    state_number: DfaStateId,
207    start_index: usize,
208    precedence: i32,
209    outer_context: ContextId,
210    force_full_context_retry: bool,
211    sll_probe_only: bool,
212}
213
214#[derive(Clone, Copy)]
215struct AdaptivePredictRequest {
216    decision: usize,
217    precedence: usize,
218    outer_context: ContextId,
219    force_full_context_retry: bool,
220    /// When set, the SLL walk stops at the first full-context-requiring conflict
221    /// and returns the SLL prediction (carrying `requires_full_context = true`)
222    /// WITHOUT running the expensive full-context LL loop. The generated
223    /// two-stage prediction uses only that boolean to decide whether to re-run
224    /// with the real outer context, so the empty-context LL pass this skips is
225    /// discarded work. Mirrors Go's execATN, which returns "needs LL" from the
226    /// SLL stage rather than computing LL twice.
227    sll_probe_only: bool,
228}
229
230#[derive(Clone, Copy)]
231struct DfaEdge {
232    decision: usize,
233    source_state: DfaStateId,
234}
235
236#[derive(Clone, Debug)]
237struct PreviousGoodAlt {
238    alt: usize,
239    configs: Vec<AtnConfig>,
240}
241
242#[derive(Clone, Debug, Eq, PartialEq)]
243struct DfaPredictionInfo {
244    prediction: ParserAtnPrediction,
245    conflicting_alts: Vec<usize>,
246}
247
248#[derive(Clone, Debug, Eq, PartialEq)]
249struct FullContextPrediction {
250    prediction: ParserAtnPrediction,
251    stop_index: usize,
252    resolution: FullContextResolution,
253}
254
255/// How the full-context loop settled, mirroring the two exits of Java's
256/// `execATNWithFullContext`: a truly unique alt (reported as context
257/// sensitivity) or a conflict resolution (reported as ambiguity, exact or
258/// not).
259#[derive(Clone, Debug, Eq, PartialEq)]
260enum FullContextResolution {
261    Unique,
262    Ambiguous { exact: bool, alts: Vec<usize> },
263}
264
265fn full_context_prediction(
266    alt: usize,
267    configs: &AtnConfigSet,
268    stop_index: usize,
269    resolution: FullContextResolution,
270) -> FullContextPrediction {
271    FullContextPrediction {
272        prediction: ParserAtnPrediction {
273            alt,
274            requires_full_context: true,
275            has_semantic_context: configs_have_semantic_context_for_alt(configs, alt),
276            diagnostic: None,
277        },
278        stop_index,
279        resolution,
280    }
281}
282
283#[derive(Clone, Debug, Eq, Hash, PartialEq)]
284struct ClosureConfigKey {
285    state: usize,
286    alt: usize,
287    context: ContextId,
288    semantic_context: SemanticContext,
289    precedence_filter_suppressed: bool,
290}
291
292impl From<&AtnConfig> for ClosureConfigKey {
293    fn from(config: &AtnConfig) -> Self {
294        Self {
295            state: config.state,
296            alt: config.alt,
297            context: config.context,
298            semantic_context: config.semantic_context.clone(),
299            precedence_filter_suppressed: config.precedence_filter_suppressed,
300        }
301    }
302}
303
304/// Reusable scratch buffers for `closure`. ANTLR's reference runtimes allocate a
305/// fresh work stack and "closure busy" visited set per `closure` call (millions
306/// of allocations on large parses); reusing one buffer across the per-config
307/// calls of a single reach/start-state computation removes that churn. Each
308/// `closure` call clears the buffers first, so the visited scope stays per-call
309/// — behaviour-identical to allocating fresh sets.
310#[derive(Default)]
311struct ClosureScratch {
312    /// Work stack of `(config, collect_predicates)`. The per-config
313    /// `collect_predicates` flag mirrors ANTLR's
314    /// `continueCollecting = collectPredicates && !ActionTransition`: once an
315    /// action edge is crossed, predicates on the far side are NOT collected into
316    /// the config's semantic context, so they are deferred to parse time rather
317    /// than evaluated during prediction (the "action hides predicates" rule).
318    stack: Vec<(AtnConfig, bool)>,
319    visited: FxHashSet<ClosureConfigKey>,
320}
321
322/// Per-closure-tree invariants, grouped so `closure` stays within Clippy's
323/// argument-count budget while threading the reusable [`ClosureScratch`].
324#[derive(Clone, Copy)]
325struct ClosureParams {
326    precedence: i32,
327    collect_predicates: bool,
328    treat_eof_as_epsilon: bool,
329}
330
331#[derive(Debug)]
332struct LookaheadIntStream {
333    symbols: Vec<i32>,
334    index: usize,
335}
336
337impl LookaheadIntStream {
338    const fn new(symbols: Vec<i32>) -> Self {
339        Self { symbols, index: 0 }
340    }
341}
342
343impl IntStream for LookaheadIntStream {
344    fn consume(&mut self) {
345        if self.la(1) != TOKEN_EOF {
346            self.index += 1;
347        }
348    }
349
350    fn la(&mut self, offset: isize) -> i32 {
351        if offset <= 0 {
352            return 0;
353        }
354        let offset = offset.cast_unsigned() - 1;
355        self.symbols
356            .get(self.index + offset)
357            .copied()
358            .unwrap_or(TOKEN_EOF)
359    }
360
361    fn index(&self) -> usize {
362        self.index
363    }
364
365    fn seek(&mut self, index: usize) {
366        self.index = index.min(self.symbols.len());
367    }
368
369    fn size(&self) -> usize {
370        self.symbols.len()
371    }
372}
373
374fn initial_decision_dfas(atn: &Atn) -> Vec<ParserDfa> {
375    atn.decision_to_state()
376        .iter()
377        .enumerate()
378        .map(|(decision, state)| {
379            let mut dfa = ParserDfa::with_max_token_type(state, decision, atn.max_token_type());
380            if atn
381                .state(state)
382                .is_some_and(AtnState::precedence_rule_decision)
383            {
384                dfa.set_precedence_dfa(true);
385            }
386            dfa
387        })
388        .collect()
389}
390
391/// Merges a dropping simulator's DFAs into tables that another simulator
392/// checked in first, losslessly. The two evolved independently (the
393/// later-constructed one started cold), so numeric state ids are not
394/// comparable — but DFA states ARE comparable by their ATN config set, the
395/// same identity `ParserDfa::add_state` dedups on. Re-keying `local`'s states into
396/// `shared`'s numbering and unioning edges/starts means overlapping
397/// simulators never lose learned coverage, however it is distributed.
398/// Walking every state is fine here: this only runs on the rare
399/// overlapping-simulators drop path.
400fn union_decision_dfas(shared: &mut Vec<ParserDfa>, local: Vec<ParserDfa>) {
401    if shared.len() != local.len() {
402        *shared = local;
403        return;
404    }
405    for (shared_dfa, local_dfa) in shared.iter_mut().zip(local) {
406        union_decision_dfa(shared_dfa, local_dfa);
407    }
408}
409
410fn union_prediction_stores(
411    shared: &mut PredictionStore,
412    mut local: PredictionStore,
413    workspace: &mut PredictionWorkspace,
414) {
415    let remap = shared.contexts.import_all(&local.contexts, workspace);
416    for dfa in &mut local.decision_to_dfa {
417        dfa.remap_contexts(&remap, &shared.contexts);
418    }
419    union_decision_dfas(&mut shared.decision_to_dfa, local.decision_to_dfa);
420}
421
422fn union_decision_dfa(shared: &mut ParserDfa, local: ParserDfa) {
423    if shared.is_precedence_dfa() != local.is_precedence_dfa() {
424        // A mode flip resets the tables (`set_precedence_dfa`), so the two are
425        // not unionable; keep whichever learned more states.
426        if local.state_count() > shared.state_count() {
427            *shared = local;
428        }
429        return;
430    }
431    // Pass 1: map every local state number to a shared state number by
432    // config-set identity, inserting the states shared has not learned.
433    // Their edges reference local numbering, so they are cleared here and
434    // re-added in pass 2 under the shared numbering.
435    let mut renumber = Vec::with_capacity(local.state_count());
436    for state in local.states() {
437        let configs = local.configs(state.id());
438        let number = shared.state_id_for_configs(configs).unwrap_or_else(|| {
439            let missing = local.clone_state_without_edges(state.id());
440            shared.insert_state(missing)
441        });
442        renumber.push(number);
443    }
444    // Pass 2: union edges, translating targets into shared numbering. The
445    // incumbent's entries win; only gaps are filled. Accept metadata needs no
446    // reconciliation: it is a pure function of the config set, and equal
447    // config sets produced it through the same accept-time computation.
448    for state in local.states() {
449        let mapped = renumber[state.id().index()];
450        for transition in state.transitions() {
451            let Some(&mapped_target) = renumber.get(transition.target.index()) else {
452                continue;
453            };
454            if shared.edge(mapped, transition.symbol).is_none() {
455                shared.add_edge(mapped, transition.symbol, mapped_target);
456            }
457        }
458    }
459    if shared.start_state().is_none()
460        && let Some(start) = local.start_state()
461        && let Some(&mapped) = renumber.get(start.index())
462    {
463        shared.set_start_state(mapped);
464    }
465    for (precedence, start) in local.precedence_start_states().iter().copied().enumerate() {
466        if start == NO_DFA_STATE {
467            continue;
468        }
469        if shared.precedence_start_state(precedence).is_none()
470            && let Some(&mapped) = renumber.get(start.index())
471        {
472            shared.set_precedence_start_state(precedence, mapped);
473        }
474    }
475}
476
477impl Drop for ParserAtnSimulator<'_> {
478    fn drop(&mut self) {
479        let Some(key) = self.shared_cache_key else {
480            return;
481        };
482        #[cfg(feature = "perf-counters")]
483        let publication_started = std::time::Instant::now();
484        #[cfg(feature = "perf-counters")]
485        let published_states = self
486            .store
487            .decision_to_dfa
488            .iter()
489            .map(ParserDfa::state_count)
490            .sum();
491        // Check the DFAs back IN by move. The slot is normally vacant because
492        // `new_shared` checked them out; it is occupied only when another
493        // simulator for the same ATN was created while this one was alive
494        // (that one started cold and checked its copy in first) — then union
495        // the two by config-set identity so neither side's learning is lost.
496        let store = std::mem::take(&mut self.store);
497        let published = SHARED_PREDICTION_STORES.with(|cache| {
498            let mut cache = cache.borrow_mut();
499            let shared = cache.entry(key).or_default();
500            if shared.generation != self.shared_cache_generation {
501                return false;
502            }
503            if let Some(shared_store) = shared.store.as_mut() {
504                union_prediction_stores(shared_store, store, &mut self.workspace);
505            } else {
506                shared.store = Some(store);
507            }
508            true
509        });
510        #[cfg(feature = "perf-counters")]
511        if published {
512            crate::perf::record_dfa_cache_publication(
513                publication_started.elapsed().as_nanos(),
514                published_states,
515            );
516        }
517        #[cfg(not(feature = "perf-counters"))]
518        let _ = published;
519    }
520}
521
522impl<'a> ParserAtnSimulator<'a> {
523    pub fn new(atn: &'a Atn) -> Self {
524        Self {
525            atn,
526            store: PredictionStore::new(atn),
527            workspace: PredictionWorkspace::default(),
528            outer_context_cache: None,
529            outer_context_cache_hits: 0,
530            outer_context_cache_misses: 0,
531            deferred_accept_states: FxHashSet::default(),
532            shared_cache_key: None,
533            shared_cache_generation: 0,
534            exact_ambig_detection: false,
535            full_context_memo: HashMap::default(),
536            full_context_memo_len: 0,
537            full_context_memo_gate: None,
538        }
539    }
540
541    /// Resets transient simulator state while retaining learned decision DFAs.
542    pub fn reset(&mut self) {
543        self.outer_context_cache = None;
544        self.deferred_accept_states.clear();
545        self.workspace.reset();
546    }
547
548    /// Clears this simulator's learned decision DFAs.
549    ///
550    /// Shared simulators also invalidate the thread-local cache generation so
551    /// an overlapping stale simulator cannot republish pre-clear states later.
552    pub fn clear_dfa(&mut self) {
553        self.store = PredictionStore::new(self.atn);
554        // The memo keys entries by ContextId into the store's arena the
555        // line above just replaced; stale IDs would alias fresh contexts.
556        self.full_context_memo.clear();
557        self.full_context_memo_len = 0;
558        self.reset();
559        if let Some(key) = self.shared_cache_key {
560            self.shared_cache_generation = clear_shared_prediction_store(key);
561        }
562    }
563
564    /// Clears the thread-local learned DFA store for a generated parser ATN.
565    pub fn clear_shared_dfa(atn: &'static Atn) {
566        let ptr: *const Atn = atn;
567        clear_shared_prediction_store(ptr as usize);
568    }
569
570    /// Switches the full-context resolution strategy (Java's
571    /// `LL_EXACT_AMBIG_DETECTION` versus plain `LL`).
572    pub const fn set_exact_ambig_detection(&mut self, exact: bool) {
573        self.exact_ambig_detection = exact;
574    }
575
576    /// Creates a simulator that starts from, and publishes back into, a
577    /// thread-local DFA cache keyed by a generated parser's static ATN.
578    ///
579    /// Generated parsers usually create a fresh parser object per parse. Without
580    /// this cache every parse relearns the same adaptive DFA; with it, later
581    /// parser instances reuse the SLL cache learned by earlier instances while
582    /// still keeping mutable simulator state local to the parser during a parse.
583    ///
584    /// The DFAs are checked OUT of the cache by move (and back in on drop):
585    /// cloning a warm DFA per parser instance costs O(learned states) — ~10%
586    /// of a small parse. A second simulator created for the same ATN while one
587    /// is alive finds the slot empty and starts cold; the drop-time check-in
588    /// then remaps its context IDs and unions both independently learned stores.
589    /// Renders every non-empty learned decision DFA in the format of Java's
590    /// `Parser.dumpDFA()` / `DFASerializer` — `Decision N:` headers followed
591    /// by `s0-'else'->:s1^=>1` edge lines — which the runtime testsuite's
592    /// `showDFA` descriptors byte-compare.
593    pub fn dump_dfa_java_style(&self, vocabulary: &crate::vocabulary::Vocabulary) -> String {
594        use std::fmt::Write as _;
595        let mut out = String::new();
596        let mut seen_one = false;
597        for dfa in &self.store.decision_to_dfa {
598            if dfa.is_empty() {
599                continue;
600            }
601            if seen_one {
602                out.push('\n');
603            }
604            seen_one = true;
605            let _ = writeln!(out, "Decision {}:", dfa.decision());
606            for state in dfa.states() {
607                let source = dfa_state_display(
608                    state,
609                    self.deferred_accept_states
610                        .contains(&(dfa.decision(), state.id())),
611                );
612                for transition in state.transitions() {
613                    let Some(target_state) = dfa.state(transition.target) else {
614                        continue;
615                    };
616                    let label = vocabulary.display_name(transition.symbol);
617                    let target = dfa_state_display(
618                        target_state,
619                        self.deferred_accept_states
620                            .contains(&(dfa.decision(), target_state.id())),
621                    );
622                    let _ = writeln!(out, "{source}-{label}->{target}");
623                }
624            }
625        }
626        out
627    }
628
629    pub fn new_shared(atn: &'static Atn) -> Self {
630        let ptr: *const Atn = atn;
631        let key = ptr as usize;
632        #[cfg(feature = "perf-counters")]
633        let import_started = std::time::Instant::now();
634        let (store, generation) = SHARED_PREDICTION_STORES.with(|cache| {
635            let mut cache = cache.borrow_mut();
636            let shared = cache.entry(key).or_default();
637            (
638                shared
639                    .store
640                    .take()
641                    .unwrap_or_else(|| PredictionStore::new(atn)),
642                shared.generation,
643            )
644        });
645        #[cfg(feature = "perf-counters")]
646        crate::perf::record_dfa_cache_import(
647            import_started.elapsed().as_nanos(),
648            store
649                .decision_to_dfa
650                .iter()
651                .map(ParserDfa::state_count)
652                .sum(),
653        );
654        Self {
655            atn,
656            store,
657            workspace: PredictionWorkspace::default(),
658            outer_context_cache: None,
659            outer_context_cache_hits: 0,
660            outer_context_cache_misses: 0,
661            deferred_accept_states: FxHashSet::default(),
662            shared_cache_key: Some(key),
663            shared_cache_generation: generation,
664            exact_ambig_detection: false,
665            full_context_memo: HashMap::default(),
666            full_context_memo_len: 0,
667            full_context_memo_gate: None,
668        }
669    }
670
671    pub fn decision_dfas(&self) -> &[ParserDfa] {
672        &self.store.decision_to_dfa
673    }
674
675    /// Returns aggregate learned parser-DFA storage and interning measurements.
676    pub fn parser_dfa_stats(&self) -> ParserDfaStats {
677        let mut stats = ParserDfaStats::default();
678        for dfa in &self.store.decision_to_dfa {
679            stats.add_assign(dfa.stats());
680        }
681        stats
682    }
683
684    /// Returns compact prediction-context allocation and interning totals for
685    /// this simulator's learned store.
686    pub fn prediction_context_stats(&self) -> PredictionContextStats {
687        let mut stats = self.store.contexts.stats();
688        stats.retained_bytes += self.workspace.retained_bytes();
689        stats.workspace_merge_cache_entries = self.workspace.merge_cache_len();
690        stats.workspace_merge_cache_capacity = self.workspace.merge_cache_capacity();
691        stats.workspace_entry_capacity = self.workspace.entry_capacity();
692        stats.outer_context_cache_hits = self.outer_context_cache_hits;
693        stats.outer_context_cache_misses = self.outer_context_cache_misses;
694        stats
695    }
696
697    /// Interns a generated parser's outer call stack in this simulator's
698    /// context arena. Return states must be supplied outermost to innermost,
699    /// and `rule_context_version` must change whenever that stack changes.
700    pub fn intern_prediction_context(
701        &mut self,
702        rule_context_version: usize,
703        return_states: impl IntoIterator<Item = usize>,
704    ) -> ContextId {
705        if let Some(cached) = self.outer_context_cache
706            && cached.rule_context_version == rule_context_version
707        {
708            self.outer_context_cache_hits = self.outer_context_cache_hits.saturating_add(1);
709            return cached.context;
710        }
711        self.outer_context_cache_misses = self.outer_context_cache_misses.saturating_add(1);
712        let mut context = EMPTY_CONTEXT;
713        for return_state in return_states {
714            context = self.store.contexts.singleton(context, return_state);
715        }
716        self.outer_context_cache = Some(CachedOuterContext {
717            rule_context_version,
718            context,
719        });
720        context
721    }
722
723    pub fn adaptive_predict(
724        &mut self,
725        decision: usize,
726        lookahead: impl IntoIterator<Item = i32>,
727    ) -> Result<usize, ParserAtnSimulatorError> {
728        self.adaptive_predict_with_precedence(decision, 0, lookahead)
729    }
730
731    pub fn adaptive_predict_stream<T: IntStream>(
732        &mut self,
733        decision: usize,
734        input: &mut T,
735    ) -> Result<usize, ParserAtnSimulatorError> {
736        self.adaptive_predict_stream_with_precedence(decision, 0, input)
737    }
738
739    pub fn adaptive_predict_stream_with_precedence<T: IntStream>(
740        &mut self,
741        decision: usize,
742        precedence: usize,
743        input: &mut T,
744    ) -> Result<usize, ParserAtnSimulatorError> {
745        self.adaptive_predict_stream_info_with_precedence(decision, precedence, input)
746            .map(|prediction| prediction.alt)
747    }
748
749    pub fn adaptive_predict_stream_info_with_precedence<T: IntStream>(
750        &mut self,
751        decision: usize,
752        precedence: usize,
753        input: &mut T,
754    ) -> Result<ParserAtnPrediction, ParserAtnSimulatorError> {
755        let marker = input.mark();
756        let index = input.index();
757        let mut workspace = std::mem::take(&mut self.workspace);
758        workspace.reset();
759        let result = self.adaptive_predict_stream_inner(
760            AdaptivePredictRequest {
761                decision,
762                precedence,
763                outer_context: EMPTY_CONTEXT,
764                force_full_context_retry: false,
765                sll_probe_only: false,
766            },
767            input,
768            &mut workspace,
769        );
770        self.workspace = workspace;
771        input.seek(index);
772        input.release(marker);
773        result
774    }
775
776    /// SLL-probe variant of [`Self::adaptive_predict_stream_info_with_precedence`].
777    ///
778    /// Identical to the precedence entry except that, when the SLL walk reaches
779    /// a conflict state requiring full context, it returns the SLL prediction
780    /// (carrying `requires_full_context = true`) WITHOUT running the
781    /// full-context LL loop. The generated two-stage prediction calls this for
782    /// stage 1 and only consults `requires_full_context` to decide whether to
783    /// re-run with the real outer context, so the empty-context LL pass this
784    /// skips would be discarded anyway. Avoids the double LL pass per escalation.
785    pub fn adaptive_predict_stream_info_sll_probe<T: IntStream>(
786        &mut self,
787        decision: usize,
788        precedence: usize,
789        input: &mut T,
790    ) -> Result<ParserAtnPrediction, ParserAtnSimulatorError> {
791        let marker = input.mark();
792        let index = input.index();
793        let mut workspace = std::mem::take(&mut self.workspace);
794        workspace.reset();
795        let result = self.adaptive_predict_stream_inner(
796            AdaptivePredictRequest {
797                decision,
798                precedence,
799                outer_context: EMPTY_CONTEXT,
800                force_full_context_retry: false,
801                sll_probe_only: true,
802            },
803            input,
804            &mut workspace,
805        );
806        self.workspace = workspace;
807        input.seek(index);
808        input.release(marker);
809        result
810    }
811
812    pub fn adaptive_predict_stream_info_with_context<T: IntStream>(
813        &mut self,
814        decision: usize,
815        precedence: usize,
816        input: &mut T,
817        outer_context: ContextId,
818    ) -> Result<ParserAtnPrediction, ParserAtnSimulatorError> {
819        self.store.contexts.assert_valid(outer_context);
820        let marker = input.mark();
821        let index = input.index();
822        let mut workspace = std::mem::take(&mut self.workspace);
823        workspace.reset();
824        let result = self.adaptive_predict_stream_inner(
825            AdaptivePredictRequest {
826                decision,
827                precedence,
828                outer_context,
829                force_full_context_retry: true,
830                sll_probe_only: false,
831            },
832            input,
833            &mut workspace,
834        );
835        self.workspace = workspace;
836        input.seek(index);
837        input.release(marker);
838        result
839    }
840
841    pub fn adaptive_predict_with_precedence(
842        &mut self,
843        decision: usize,
844        precedence: usize,
845        lookahead: impl IntoIterator<Item = i32>,
846    ) -> Result<usize, ParserAtnSimulatorError> {
847        self.adaptive_predict_info_with_precedence(decision, precedence, lookahead)
848            .map(|prediction| prediction.alt)
849    }
850
851    pub fn adaptive_predict_info_with_precedence(
852        &mut self,
853        decision: usize,
854        precedence: usize,
855        lookahead: impl IntoIterator<Item = i32>,
856    ) -> Result<ParserAtnPrediction, ParserAtnSimulatorError> {
857        let mut input = LookaheadIntStream::new(lookahead.into_iter().collect());
858        self.adaptive_predict_stream_info_with_precedence(decision, precedence, &mut input)
859    }
860
861    fn adaptive_predict_stream_inner<T: IntStream>(
862        &mut self,
863        request: AdaptivePredictRequest,
864        input: &mut T,
865        merge_cache: &mut PredictionWorkspace,
866    ) -> Result<ParserAtnPrediction, ParserAtnSimulatorError> {
867        let AdaptivePredictRequest {
868            decision,
869            precedence,
870            outer_context,
871            force_full_context_retry,
872            sll_probe_only,
873        } = request;
874        self.deferred_accept_states
875            .retain(|(stored_decision, _)| *stored_decision != decision);
876        #[cfg(feature = "perf-counters")]
877        crate::perf::record_adaptive_call(decision, force_full_context_retry);
878        let Some(decision_state) = self.atn.decision_to_state().get(decision) else {
879            return Err(ParserAtnSimulatorError::UnknownDecision(decision));
880        };
881        let start_index = input.index();
882        // Precedence originates from the parser's precedence stack (rule nesting
883        // depth), so it is always small in practice. A value above `i32::MAX`
884        // would be clamped here; the clamp only ever affects pathological inputs
885        // and at worst over-filters precedence transitions, never miscomputing a
886        // real parse.
887        let precedence = i32::try_from(precedence).unwrap_or(i32::MAX);
888        let mut state_number =
889            self.ensure_start_state(decision, decision_state, precedence, merge_cache)?;
890        // The direct interpreter API can continue past a completed prefix, but
891        // generated parsers retain standard SLL early termination.
892        let track_previous_good_alt = !force_full_context_retry && !sll_probe_only;
893        let mut previous_good_alt = None;
894        if let Some(prediction) = self.prediction_or_full_context(
895            input,
896            PredictionCheck {
897                decision,
898                decision_state,
899                state_number,
900                start_index,
901                precedence,
902                outer_context,
903                force_full_context_retry,
904                sll_probe_only,
905            },
906            merge_cache,
907        )? {
908            return Ok(prediction);
909        }
910        loop {
911            if track_previous_good_alt {
912                let finished = self
913                    .store
914                    .decision_to_dfa
915                    .get(decision)
916                    .map(|dfa| dfa.configs(state_number))
917                    .and_then(|configs| self.previous_good_alt(configs));
918                if finished.is_some() {
919                    previous_good_alt = finished;
920                }
921            }
922            let symbol = input.la(1);
923            let target = self
924                .store
925                .decision_to_dfa
926                .get(decision)
927                .and_then(|dfa| dfa.edge(state_number, symbol));
928            #[cfg(feature = "perf-counters")]
929            crate::perf::record_dfa_edge_lookup(target.is_some());
930            if let Some(target) = target {
931                state_number = target;
932            } else {
933                let configs = self
934                    .store
935                    .decision_to_dfa
936                    .get(decision)
937                    .map(|dfa| dfa.configs(state_number).clone())
938                    .ok_or(ParserAtnSimulatorError::MissingDfaState(state_number))?;
939                let edge = DfaEdge {
940                    decision,
941                    source_state: state_number,
942                };
943                let target = match self.compute_target_state(
944                    edge,
945                    &configs,
946                    symbol,
947                    precedence,
948                    merge_cache,
949                ) {
950                    Ok(target) => target,
951                    Err(ParserAtnSimulatorError::NoViableAlt { symbol, .. }) => {
952                        if let Some(fallback) = previous_good_alt.as_ref() {
953                            self.add_previous_good_alt_target(edge, symbol, fallback, merge_cache)
954                        } else {
955                            return Err(ParserAtnSimulatorError::NoViableAlt {
956                                symbol,
957                                index: input.index(),
958                            });
959                        }
960                    }
961                    Err(error) => return Err(error),
962                };
963                state_number = target;
964            }
965            if let Some(prediction) = self.prediction_or_full_context(
966                input,
967                PredictionCheck {
968                    decision,
969                    decision_state,
970                    state_number,
971                    start_index,
972                    precedence,
973                    outer_context,
974                    force_full_context_retry,
975                    sll_probe_only,
976                },
977                merge_cache,
978            )? {
979                let defer_unique = track_previous_good_alt
980                    && previous_good_alt.is_some()
981                    && !prediction.requires_full_context
982                    && !self.prediction_reached_decision_entry_rule_stop(
983                        DfaEdge {
984                            decision,
985                            source_state: state_number,
986                        },
987                        prediction.alt,
988                        precedence,
989                        symbol,
990                        merge_cache,
991                    );
992                if !defer_unique {
993                    return Ok(prediction);
994                }
995                self.deferred_accept_states.insert((decision, state_number));
996            }
997            if symbol == TOKEN_EOF {
998                // We ran out of input while still inside the decision and the
999                // current state is not a clean accept. ANTLR's execATN takes one
1000                // more step on EOF, reaches an empty reach set, and falls back to
1001                // getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule: any alt
1002                // whose configs already reached the decision's rule-stop (i.e. an
1003                // exit alt of a `(...)*`/`(...)+`/precedence loop) is a valid
1004                // prediction, not a syntax error. Mirror that fallback here so we
1005                // exit the loop cleanly instead of reporting a spurious
1006                // "no viable alternative at input '<EOF>'".
1007                if let Some(configs) = self
1008                    .store
1009                    .decision_to_dfa
1010                    .get(decision)
1011                    .map(|dfa| dfa.configs(state_number).clone())
1012                    && let Some(alt) = self.alt_that_finished_decision_entry_rule(&configs)
1013                {
1014                    return Ok(ParserAtnPrediction {
1015                        alt,
1016                        requires_full_context: false,
1017                        has_semantic_context: configs_have_semantic_context_for_alt(&configs, alt),
1018                        diagnostic: None,
1019                    });
1020                }
1021                return Err(ParserAtnSimulatorError::PredictionRequiresMoreLookahead);
1022            }
1023            input.consume();
1024        }
1025    }
1026
1027    fn prediction_or_full_context<T: IntStream>(
1028        &mut self,
1029        input: &mut T,
1030        check: PredictionCheck,
1031        merge_cache: &mut PredictionWorkspace,
1032    ) -> Result<Option<ParserAtnPrediction>, ParserAtnSimulatorError> {
1033        let PredictionCheck {
1034            decision,
1035            decision_state,
1036            state_number,
1037            start_index,
1038            precedence,
1039            outer_context,
1040            force_full_context_retry,
1041            sll_probe_only,
1042        } = check;
1043        if self.store.contexts.is_empty(outer_context)
1044            && let Some(prediction) =
1045                self.non_greedy_exit_prediction(decision, decision_state, state_number)
1046        {
1047            return Ok(Some(prediction));
1048        }
1049        let Some(info) = self.dfa_prediction_info(decision, state_number) else {
1050            return Ok(None);
1051        };
1052        let prediction = info.prediction;
1053        // SLL-probe stage: the caller only needs to know that this conflict
1054        // requires full context; it will re-run with the real outer context.
1055        // Returning the SLL prediction here (with requires_full_context set)
1056        // avoids running the full-context LL loop with the empty probe context,
1057        // whose result the generated two-stage code discards. Mirrors Go's
1058        // execATN, which signals "needs LL" instead of computing LL twice.
1059        if sll_probe_only && prediction.requires_full_context {
1060            return Ok(Some(prediction));
1061        }
1062        if prediction.requires_full_context
1063            && (force_full_context_retry || !prediction.has_semantic_context)
1064        {
1065            #[cfg(feature = "perf-counters")]
1066            crate::perf::record_full_context_retry(decision);
1067            let sll_stop_index = input.index();
1068            input.seek(start_index);
1069            let memo_allowed = self.full_context_memo_allowed();
1070            let memo_key = FullContextMemoKey {
1071                decision,
1072                precedence,
1073                outer_context,
1074                first_symbol: 0,
1075            };
1076            // A memo hit leaves the cursor at the replayed stop index —
1077            // exactly where the fresh LL loop below would have left it.
1078            if memo_allowed
1079                && let Some(full_context) = self.probe_full_context_memo(memo_key, input)
1080            {
1081                #[cfg(feature = "perf-counters")]
1082                crate::perf::record_full_context_memo_hit(decision);
1083                return Ok(Some(Self::full_context_retry_prediction(
1084                    full_context,
1085                    info.conflicting_alts,
1086                    start_index,
1087                    sll_stop_index,
1088                )));
1089            }
1090            let full_context = self.adaptive_predict_full_context(
1091                decision_state,
1092                input,
1093                precedence,
1094                outer_context,
1095                merge_cache,
1096            )?;
1097            if memo_allowed {
1098                self.record_full_context_memo(memo_key, start_index, input, &full_context);
1099            }
1100            return Ok(Some(Self::full_context_retry_prediction(
1101                full_context,
1102                info.conflicting_alts,
1103                start_index,
1104                sll_stop_index,
1105            )));
1106        }
1107        Ok(Some(prediction))
1108    }
1109
1110    /// Builds the prediction (and diagnostic) a full-context retry reports,
1111    /// shared by the fresh LL run and the memoized replay so both produce
1112    /// byte-identical diagnostics.
1113    fn full_context_retry_prediction(
1114        full_context: FullContextPrediction,
1115        sll_conflicting_alts: Vec<usize>,
1116        start_index: usize,
1117        sll_stop_index: usize,
1118    ) -> ParserAtnPrediction {
1119        let (kind, exact, conflicting_alts) = match full_context.resolution {
1120            FullContextResolution::Ambiguous { exact, ref alts } => (
1121                ParserAtnPredictionDiagnosticKind::Ambiguity,
1122                exact,
1123                alts.clone(),
1124            ),
1125            // A unique full-context alt after an SLL conflict is Java's
1126            // reportContextSensitivity; the SLL state's conflicting alts
1127            // describe the conflict that forced the retry.
1128            FullContextResolution::Unique => (
1129                ParserAtnPredictionDiagnosticKind::ContextSensitivity,
1130                false,
1131                sll_conflicting_alts,
1132            ),
1133        };
1134        let mut prediction = full_context.prediction;
1135        if conflicting_alts.len() > 1 {
1136            prediction.diagnostic = Some(ParserAtnPredictionDiagnostic {
1137                kind,
1138                start_index,
1139                sll_stop_index,
1140                ll_stop_index: full_context.stop_index,
1141                conflicting_alts,
1142                exact,
1143            });
1144        }
1145        prediction
1146    }
1147
1148    /// Whether full-context memoization is sound for this ATN.
1149    ///
1150    /// Predicates make prediction outcomes depend on caller-side evaluation
1151    /// state, so any predicate transition disables the memo. Action and
1152    /// precedence transitions do NOT: upstream `ActionTransition.isEpsilon()`
1153    /// is true ("we are to be ignored by analysis 'cept for predicates") and
1154    /// never contributes to an LL outcome, and a precedence transition in
1155    /// full-context mode resolves immediately against the passed precedence
1156    /// (see the `!full_context` guard in `epsilon_target_config`) — which is
1157    /// already part of the memo key. Gating on all semantic transitions would
1158    /// turn the memo off for every grammar with a left-recursive rule.
1159    ///
1160    /// Exact-ambiguity detection changes how far the LL loop consumes, so
1161    /// entries recorded under one mode must not replay under the other —
1162    /// rather than key the mode, the memo simply stays off in the diagnostic
1163    /// mode.
1164    fn full_context_memo_allowed(&mut self) -> bool {
1165        if self.exact_ambig_detection {
1166            return false;
1167        }
1168        let atn = self.atn;
1169        *self
1170            .full_context_memo_gate
1171            .get_or_insert_with(|| !atn_has_predicate_transition(atn))
1172    }
1173
1174    /// Returns the memoized LL resolution whose recorded token window matches
1175    /// the upcoming input exactly, if any. The caller must have positioned
1176    /// `input` at the decision's start index.
1177    ///
1178    /// The compare walks the stream exactly as the recorded LL loop did
1179    /// (`la(1)` at each cursor position, `consume` between), so a hit is
1180    /// literally the same computation replayed: same decision, precedence,
1181    /// interned caller context, and token sequence. On a hit the cursor is
1182    /// left at the replayed stop index — where the fresh LL loop would have
1183    /// left it; on a miss it is restored to the start.
1184    fn probe_full_context_memo<T: IntStream>(
1185        &self,
1186        mut key: FullContextMemoKey,
1187        input: &mut T,
1188    ) -> Option<FullContextPrediction> {
1189        if self.full_context_memo.is_empty() {
1190            return None;
1191        }
1192        let start_index = input.index();
1193        key.first_symbol = input.la(1);
1194        let entries = self.full_context_memo.get(&key)?;
1195        // For the keyword-vs-identifier ambiguity shape, occurrences of the
1196        // same keyword share `first_symbol`, so a hot decision's entries can
1197        // funnel into one bucket — distinguished only by their windows. The
1198        // scan is first-match-wins, which is correct because windows under a
1199        // key are prefix-free: the LL loop's stop position is a function of
1200        // key + consumed prefix, so no recorded window can be a strict prefix
1201        // of another. Each rejected candidate costs its matched-prefix length
1202        // in `consume`/`la` calls before the cursor restore; the global entry
1203        // cap bounds the worst case.
1204        'candidates: for entry in entries {
1205            for &expected in &entry.window_tail {
1206                input.consume();
1207                if input.la(1) != expected {
1208                    input.seek(start_index);
1209                    continue 'candidates;
1210                }
1211            }
1212            let mut replay = entry.prediction.clone();
1213            replay.stop_index = input.index();
1214            return Some(replay);
1215        }
1216        None
1217    }
1218
1219    /// Records a fresh full-context resolution for later replay.
1220    ///
1221    /// The recorded window re-walks the visible tokens the LL loop read
1222    /// (`start_index..=stop_index` in cursor positions); windows longer than
1223    /// [`FULL_CONTEXT_MEMO_MAX_WINDOW`] are skipped, as is everything once
1224    /// the memo holds [`FULL_CONTEXT_MEMO_MAX_ENTRIES`].
1225    fn record_full_context_memo<T: IntStream>(
1226        &mut self,
1227        mut key: FullContextMemoKey,
1228        start_index: usize,
1229        input: &mut T,
1230        full_context: &FullContextPrediction,
1231    ) {
1232        if self.full_context_memo_len >= FULL_CONTEXT_MEMO_MAX_ENTRIES {
1233            #[cfg(feature = "perf-counters")]
1234            crate::perf::record_full_context_memo_declined(key.decision);
1235            return;
1236        }
1237        let current = input.index();
1238        input.seek(start_index);
1239        key.first_symbol = input.la(1);
1240        let mut window_tail = Vec::new();
1241        while input.index() < full_context.stop_index
1242            && window_tail.len() < FULL_CONTEXT_MEMO_MAX_WINDOW
1243        {
1244            input.consume();
1245            window_tail.push(input.la(1));
1246        }
1247        let complete = input.index() >= full_context.stop_index;
1248        input.seek(current);
1249        if !complete {
1250            #[cfg(feature = "perf-counters")]
1251            crate::perf::record_full_context_memo_declined(key.decision);
1252            return;
1253        }
1254        self.full_context_memo
1255            .entry(key)
1256            .or_default()
1257            .push(FullContextMemoEntry {
1258                window_tail,
1259                prediction: full_context.clone(),
1260            });
1261        self.full_context_memo_len += 1;
1262    }
1263
1264    fn non_greedy_exit_prediction(
1265        &self,
1266        decision: usize,
1267        decision_state: usize,
1268        state_number: DfaStateId,
1269    ) -> Option<ParserAtnPrediction> {
1270        if !self
1271            .atn
1272            .state(decision_state)
1273            .is_some_and(AtnState::non_greedy)
1274        {
1275            return None;
1276        }
1277        let configs = &self
1278            .store
1279            .decision_to_dfa
1280            .get(decision)?
1281            .configs(state_number);
1282        let alt = configs
1283            .configs()
1284            .iter()
1285            .filter(|config| {
1286                self.atn
1287                    .state(config.state)
1288                    .is_some_and(AtnState::is_rule_stop)
1289                    && self.store.contexts.has_empty_path(config.context)
1290            })
1291            .map(|config| config.alt)
1292            .min()?;
1293        Some(ParserAtnPrediction {
1294            alt,
1295            requires_full_context: false,
1296            has_semantic_context: configs_have_semantic_context_for_alt(configs, alt),
1297            diagnostic: None,
1298        })
1299    }
1300
1301    fn ensure_start_state(
1302        &mut self,
1303        decision: usize,
1304        decision_state: usize,
1305        precedence: i32,
1306        merge_cache: &mut PredictionWorkspace,
1307    ) -> Result<DfaStateId, ParserAtnSimulatorError> {
1308        if self.store.decision_to_dfa[decision].is_precedence_dfa() {
1309            let precedence_key = usize::try_from(precedence.max(0)).unwrap_or_default();
1310            if let Some(start) =
1311                self.store.decision_to_dfa[decision].precedence_start_state(precedence_key)
1312            {
1313                return Ok(start);
1314            }
1315        } else if let Some(start) = self.store.decision_to_dfa[decision].start_state() {
1316            return Ok(start);
1317        }
1318        let decision_state = self
1319            .atn
1320            .state(decision_state)
1321            .ok_or(ParserAtnSimulatorError::MissingAtnState(decision_state))?;
1322        let configs = self.compute_start_state(decision_state, precedence, merge_cache);
1323        let state_number = self.add_dfa_state(decision, DfaStateBuilder::new(configs));
1324        if self.store.decision_to_dfa[decision].is_precedence_dfa() {
1325            let precedence_key = usize::try_from(precedence.max(0)).unwrap_or_default();
1326            self.store.decision_to_dfa[decision]
1327                .set_precedence_start_state(precedence_key, state_number);
1328        } else {
1329            self.store.decision_to_dfa[decision].set_start_state(state_number);
1330        }
1331        Ok(state_number)
1332    }
1333
1334    fn add_dfa_state(&mut self, decision: usize, state: DfaStateBuilder) -> DfaStateId {
1335        self.store.decision_to_dfa[decision].add_state(state)
1336    }
1337
1338    fn compute_start_state(
1339        &mut self,
1340        decision_state: AtnState<'_>,
1341        precedence: i32,
1342        merge_cache: &mut PredictionWorkspace,
1343    ) -> AtnConfigSet {
1344        self.compute_start_state_with_context(
1345            decision_state,
1346            false,
1347            EMPTY_CONTEXT,
1348            precedence,
1349            merge_cache,
1350        )
1351    }
1352
1353    fn compute_start_state_with_context(
1354        &mut self,
1355        decision_state: AtnState<'_>,
1356        full_context: bool,
1357        initial_context: ContextId,
1358        precedence: i32,
1359        merge_cache: &mut PredictionWorkspace,
1360    ) -> AtnConfigSet {
1361        let mut configs = AtnConfigSet::new_full_context(full_context);
1362        let mut scratch = ClosureScratch::default();
1363        let params = ClosureParams {
1364            precedence,
1365            collect_predicates: true,
1366            treat_eof_as_epsilon: false,
1367        };
1368        for (index, transition) in decision_state.transitions().iter().enumerate() {
1369            let alt = index + 1;
1370            let config = AtnConfig::new(
1371                transition.target(),
1372                alt,
1373                initial_context,
1374                &self.store.contexts,
1375            );
1376            self.closure(config, &mut configs, merge_cache, &mut scratch, params);
1377        }
1378        configs
1379    }
1380
1381    fn adaptive_predict_full_context<T: IntStream>(
1382        &mut self,
1383        decision_state: usize,
1384        input: &mut T,
1385        precedence: i32,
1386        outer_context: ContextId,
1387        merge_cache: &mut PredictionWorkspace,
1388    ) -> Result<FullContextPrediction, ParserAtnSimulatorError> {
1389        let decision_state = self
1390            .atn
1391            .state(decision_state)
1392            .ok_or(ParserAtnSimulatorError::MissingAtnState(decision_state))?;
1393        let mut configs = self.compute_start_state_with_context(
1394            decision_state,
1395            true,
1396            outer_context,
1397            precedence,
1398            merge_cache,
1399        );
1400        // Java's `execATNWithFullContext`: after each reach set a truly
1401        // unique alt resolves as context sensitivity. Otherwise default LL
1402        // mode stops at the first "resolves to just one viable alt" conflict
1403        // — reported as a NON-exact ambiguity, which the exactOnly listener
1404        // suppresses — while LL_EXACT_AMBIG_DETECTION keeps consuming until
1405        // every (state, context) subset conflicts over the same alt set: an
1406        // exact ambiguity.
1407        loop {
1408            if let Some(alt) = configs.unique_alt() {
1409                return Ok(full_context_prediction(
1410                    alt,
1411                    &configs,
1412                    input.index(),
1413                    FullContextResolution::Unique,
1414                ));
1415            }
1416            let symbol = input.la(1);
1417            let reach = self.compute_reach_set(&configs, symbol, true, precedence, merge_cache);
1418            if reach.is_empty() {
1419                return Err(ParserAtnSimulatorError::NoViableAlt {
1420                    symbol,
1421                    index: input.index(),
1422                });
1423            }
1424            configs = reach;
1425            if let Some(alt) = configs.unique_alt() {
1426                return Ok(full_context_prediction(
1427                    alt,
1428                    &configs,
1429                    input.index(),
1430                    FullContextResolution::Unique,
1431                ));
1432            }
1433            if !configs.has_semantic_context() {
1434                let subsets = conflicting_alt_subsets(configs.configs());
1435                if self.exact_ambig_detection {
1436                    let alts: Vec<usize> = configs.alts().into_iter().collect();
1437                    // Both subset checks hold vacuously for an empty list; a
1438                    // real exact ambiguity always carries alternatives, so
1439                    // guard the pick instead of indexing.
1440                    if all_subsets_conflict(&subsets)
1441                        && all_subsets_equal(&subsets)
1442                        && let Some(&alt) = alts.first()
1443                    {
1444                        return Ok(full_context_prediction(
1445                            alt,
1446                            &configs,
1447                            input.index(),
1448                            FullContextResolution::Ambiguous { exact: true, alts },
1449                        ));
1450                    }
1451                } else if let Some(alt) = single_viable_alt(&subsets) {
1452                    let alts: Vec<usize> = configs.alts().into_iter().collect();
1453                    return Ok(full_context_prediction(
1454                        alt,
1455                        &configs,
1456                        input.index(),
1457                        FullContextResolution::Ambiguous { exact: false, alts },
1458                    ));
1459                }
1460            }
1461            if symbol == TOKEN_EOF || self.configs_all_reached_rule_stop(&configs) {
1462                // Safety net Java reaches implicitly: at EOF every surviving
1463                // path sits in a rule-stop config, so the checks above
1464                // resolve; guard against pathological sets instead of
1465                // spinning on an unconsumable EOF.
1466                let alts: Vec<usize> = configs.alts().into_iter().collect();
1467                let alt = *alts
1468                    .first()
1469                    .ok_or(ParserAtnSimulatorError::PredictionRequiresMoreLookahead)?;
1470                let resolution = if alts.len() > 1 {
1471                    FullContextResolution::Ambiguous {
1472                        exact: self.exact_ambig_detection,
1473                        alts,
1474                    }
1475                } else {
1476                    FullContextResolution::Unique
1477                };
1478                return Ok(full_context_prediction(
1479                    alt,
1480                    &configs,
1481                    input.index(),
1482                    resolution,
1483                ));
1484            }
1485            input.consume();
1486        }
1487    }
1488
1489    fn compute_target_state(
1490        &mut self,
1491        edge: DfaEdge,
1492        configs: &AtnConfigSet,
1493        symbol: i32,
1494        precedence: i32,
1495        merge_cache: &mut PredictionWorkspace,
1496    ) -> Result<DfaStateId, ParserAtnSimulatorError> {
1497        let mut reach = self.compute_reach_set(configs, symbol, false, precedence, merge_cache);
1498        if reach.is_empty() {
1499            if let Some(prediction) = self.alt_that_finished_decision_entry_rule(configs) {
1500                let mut dfa_state = DfaStateBuilder::new(configs.clone());
1501                dfa_state.mark_accept(prediction);
1502                // The set-wide flag gates the per-alt scan: if no config in the
1503                // set carries a semantic context, no alt can either.
1504                dfa_state.set_has_semantic_context_for_alt(
1505                    configs.has_semantic_context()
1506                        && configs_have_semantic_context_for_alt(configs, prediction),
1507                );
1508                let target_state = self.add_dfa_state(edge.decision, dfa_state);
1509                self.store.decision_to_dfa[edge.decision].add_edge(
1510                    edge.source_state,
1511                    symbol,
1512                    target_state,
1513                );
1514                return Ok(target_state);
1515            }
1516            return Err(ParserAtnSimulatorError::NoViableAlt { symbol, index: 0 });
1517        }
1518        let prediction = reach.unique_alt();
1519        let conflict_prediction = prediction.or_else(|| {
1520            if !has_sll_conflict_terminating_prediction(&reach, |state| {
1521                self.atn.state(state).is_some_and(AtnState::is_rule_stop)
1522            }) {
1523                return None;
1524            }
1525            reach
1526                .conflicting_alts()
1527                .into_iter()
1528                .next()
1529                .or_else(|| reach.alts().into_iter().next())
1530        });
1531        let requires_full_context = prediction.is_none() && conflict_prediction.is_some();
1532        #[cfg(feature = "perf-counters")]
1533        if requires_full_context {
1534            crate::perf::record_sll_conflict(edge.decision);
1535        }
1536        let conflicting_alts = if requires_full_context {
1537            let alts = reach.conflicting_alts();
1538            if alts.is_empty() { reach.alts() } else { alts }
1539                .into_iter()
1540                .collect()
1541        } else {
1542            Vec::new()
1543        };
1544        let mut dfa_state = DfaStateBuilder::new(reach);
1545        if let Some(prediction) = conflict_prediction {
1546            dfa_state.mark_accept(prediction);
1547            dfa_state.set_requires_full_context(requires_full_context);
1548            dfa_state.set_conflicting_alts(conflicting_alts);
1549            // The set-wide flag gates the per-alt scan: if no config in the set
1550            // carries a semantic context, no alt can either.
1551            dfa_state.set_has_semantic_context_for_alt(
1552                dfa_state.configs.has_semantic_context()
1553                    && configs_have_semantic_context_for_alt(&dfa_state.configs, prediction),
1554            );
1555        }
1556        let target_state = self.add_dfa_state(edge.decision, dfa_state);
1557        self.store.decision_to_dfa[edge.decision].add_edge(edge.source_state, symbol, target_state);
1558        Ok(target_state)
1559    }
1560
1561    fn compute_reach_set(
1562        &mut self,
1563        configs: &AtnConfigSet,
1564        symbol: i32,
1565        full_context: bool,
1566        precedence: i32,
1567        merge_cache: &mut PredictionWorkspace,
1568    ) -> AtnConfigSet {
1569        let mut intermediate = AtnConfigSet::new_full_context(full_context);
1570        let mut skipped_stop_states = Vec::new();
1571        let max_token_type = self.atn.max_token_type();
1572        for config in configs.configs() {
1573            let Some(state) = self.atn.state(config.state) else {
1574                continue;
1575            };
1576            if state.is_rule_stop() {
1577                if full_context || symbol == TOKEN_EOF {
1578                    skipped_stop_states.push(config.clone());
1579                }
1580                continue;
1581            }
1582            for transition in &state.transitions() {
1583                if transition.matches(symbol, 1, max_token_type) {
1584                    let target =
1585                        config.moved_to(transition.target(), config.context, &self.store.contexts);
1586                    intermediate.add(target, &mut self.store.contexts, merge_cache);
1587                }
1588            }
1589        }
1590        let mut reach = if skipped_stop_states.is_empty() && symbol != TOKEN_EOF {
1591            if intermediate.len() == 1 || intermediate.unique_alt().is_some() {
1592                intermediate
1593            } else {
1594                self.close_intermediate_reach_set(
1595                    intermediate,
1596                    full_context,
1597                    precedence,
1598                    symbol,
1599                    merge_cache,
1600                )
1601            }
1602        } else {
1603            self.close_intermediate_reach_set(
1604                intermediate,
1605                full_context,
1606                precedence,
1607                symbol,
1608                merge_cache,
1609            )
1610        };
1611        if symbol == TOKEN_EOF {
1612            reach = self.rule_stop_configs(reach, merge_cache);
1613        }
1614        if !full_context || !self.configs_contain_rule_stop(&reach) {
1615            for config in skipped_stop_states {
1616                reach.add(config, &mut self.store.contexts, merge_cache);
1617            }
1618        }
1619        #[cfg(feature = "perf-counters")]
1620        crate::perf::record_reach_set(full_context, configs.len(), reach.len());
1621        reach
1622    }
1623
1624    fn close_intermediate_reach_set(
1625        &mut self,
1626        intermediate: AtnConfigSet,
1627        full_context: bool,
1628        precedence: i32,
1629        symbol: i32,
1630        merge_cache: &mut PredictionWorkspace,
1631    ) -> AtnConfigSet {
1632        let mut reach = AtnConfigSet::new_full_context(full_context);
1633        let mut scratch = ClosureScratch::default();
1634        let params = ClosureParams {
1635            precedence,
1636            collect_predicates: false,
1637            treat_eof_as_epsilon: symbol == TOKEN_EOF,
1638        };
1639        // `closure` takes `AtnConfig` by value, so drain the intermediate set by
1640        // move instead of cloning each config.
1641        for config in intermediate.into_configs() {
1642            self.closure(config, &mut reach, merge_cache, &mut scratch, params);
1643        }
1644        reach
1645    }
1646
1647    fn alt_that_finished_decision_entry_rule(&self, configs: &AtnConfigSet) -> Option<usize> {
1648        configs
1649            .configs()
1650            .iter()
1651            .filter(|config| self.config_finished_decision_entry_rule(config))
1652            .map(|config| config.alt)
1653            .min()
1654    }
1655
1656    fn previous_good_alt(&self, configs: &AtnConfigSet) -> Option<PreviousGoodAlt> {
1657        let alt = self.alt_that_finished_decision_entry_rule(configs)?;
1658        let configs = configs
1659            .configs()
1660            .iter()
1661            .filter(|config| config.alt == alt && self.config_finished_decision_entry_rule(config))
1662            .cloned()
1663            .collect();
1664        Some(PreviousGoodAlt { alt, configs })
1665    }
1666
1667    fn config_finished_decision_entry_rule(&self, config: &AtnConfig) -> bool {
1668        config.reaches_into_outer_context > 0
1669            || self
1670                .atn
1671                .state(config.state)
1672                .is_some_and(AtnState::is_rule_stop)
1673                && self.store.contexts.has_empty_path(config.context)
1674    }
1675
1676    fn add_previous_good_alt_target(
1677        &mut self,
1678        edge: DfaEdge,
1679        symbol: i32,
1680        fallback: &PreviousGoodAlt,
1681        merge_cache: &mut PredictionWorkspace,
1682    ) -> DfaStateId {
1683        let mut configs = AtnConfigSet::new();
1684        for config in &fallback.configs {
1685            configs.add(config.clone(), &mut self.store.contexts, merge_cache);
1686        }
1687        let has_semantic_context = configs_have_semantic_context_for_alt(&configs, fallback.alt);
1688        let mut state = DfaStateBuilder::new(configs);
1689        state.mark_accept(fallback.alt);
1690        state.set_has_semantic_context_for_alt(has_semantic_context);
1691        let target = self.add_dfa_state(edge.decision, state);
1692        self.store.decision_to_dfa[edge.decision].add_edge(edge.source_state, symbol, target);
1693        target
1694    }
1695
1696    fn prediction_reached_decision_entry_rule_stop(
1697        &mut self,
1698        edge: DfaEdge,
1699        alt: usize,
1700        precedence: i32,
1701        symbol: i32,
1702        merge_cache: &mut PredictionWorkspace,
1703    ) -> bool {
1704        let configs = self.store.decision_to_dfa[edge.decision]
1705            .configs(edge.source_state)
1706            .clone();
1707        if self.alt_that_finished_decision_entry_rule(&configs) == Some(alt) {
1708            return true;
1709        }
1710        let closed =
1711            self.close_intermediate_reach_set(configs, false, precedence, symbol, merge_cache);
1712        self.alt_that_finished_decision_entry_rule(&closed) == Some(alt)
1713    }
1714
1715    fn rule_stop_configs(
1716        &mut self,
1717        configs: AtnConfigSet,
1718        merge_cache: &mut PredictionWorkspace,
1719    ) -> AtnConfigSet {
1720        if configs.configs().iter().all(|config| {
1721            self.atn
1722                .state(config.state)
1723                .is_some_and(AtnState::is_rule_stop)
1724        }) {
1725            return configs;
1726        }
1727        let mut result = AtnConfigSet::new_full_context(configs.full_context());
1728        for config in configs.configs().iter().filter(|config| {
1729            self.atn
1730                .state(config.state)
1731                .is_some_and(AtnState::is_rule_stop)
1732        }) {
1733            result.add(config.clone(), &mut self.store.contexts, merge_cache);
1734        }
1735        result
1736    }
1737
1738    fn configs_all_reached_rule_stop(&self, configs: &AtnConfigSet) -> bool {
1739        configs.configs().iter().all(|config| {
1740            self.atn
1741                .state(config.state)
1742                .is_some_and(AtnState::is_rule_stop)
1743        })
1744    }
1745
1746    fn configs_contain_rule_stop(&self, configs: &AtnConfigSet) -> bool {
1747        configs.configs().iter().any(|config| {
1748            self.atn
1749                .state(config.state)
1750                .is_some_and(AtnState::is_rule_stop)
1751        })
1752    }
1753
1754    fn closure(
1755        &mut self,
1756        config: AtnConfig,
1757        configs: &mut AtnConfigSet,
1758        merge_cache: &mut PredictionWorkspace,
1759        scratch: &mut ClosureScratch,
1760        params: ClosureParams,
1761    ) {
1762        let ClosureParams {
1763            precedence,
1764            collect_predicates,
1765            treat_eof_as_epsilon,
1766        } = params;
1767        let max_token_type = self.atn.max_token_type();
1768        scratch.stack.clear();
1769        scratch.visited.clear();
1770        scratch.stack.push((config, collect_predicates));
1771        while let Some((config, collect_predicates)) = scratch.stack.pop() {
1772            if !scratch.visited.insert(ClosureConfigKey::from(&config)) {
1773                continue;
1774            }
1775            let Some(state) = self.atn.state(config.state) else {
1776                continue;
1777            };
1778            let at_rule_stop = state.is_rule_stop();
1779            if at_rule_stop
1780                && self.closure_at_rule_stop(
1781                    config.clone(),
1782                    collect_predicates,
1783                    configs,
1784                    merge_cache,
1785                    &mut scratch.stack,
1786                )
1787            {
1788                continue;
1789            }
1790            let epsilon_only = state.epsilon_only();
1791            if !epsilon_only {
1792                configs.add(config.clone(), &mut self.store.contexts, merge_cache);
1793            }
1794            for (index, transition) in state.transitions().iter().enumerate() {
1795                if index == 0
1796                    && can_drop_left_recursive_loop_entry_edge(
1797                        self.atn,
1798                        state,
1799                        &self.store.contexts,
1800                        config.context,
1801                    )
1802                {
1803                    continue;
1804                }
1805                let transition_kind = transition.kind();
1806                if matches!(
1807                    transition_kind,
1808                    ParserTransitionKind::Epsilon
1809                        | ParserTransitionKind::Rule
1810                        | ParserTransitionKind::Predicate
1811                        | ParserTransitionKind::Action
1812                        | ParserTransitionKind::Precedence
1813                ) {
1814                    if let Some(mut target) = self.epsilon_target_config(
1815                        &config,
1816                        transition,
1817                        transition_kind,
1818                        precedence,
1819                        collect_predicates,
1820                        configs.full_context(),
1821                    ) {
1822                        if at_rule_stop {
1823                            target.reaches_into_outer_context =
1824                                target.reaches_into_outer_context.saturating_add(1);
1825                        }
1826                        // ANTLR: stop collecting predicates once an action edge is
1827                        // crossed, so a predicate after an action is deferred to
1828                        // parse time rather than evaluated during prediction.
1829                        let target_collect_predicates =
1830                            collect_predicates && transition_kind != ParserTransitionKind::Action;
1831                        scratch.stack.push((target, target_collect_predicates));
1832                    }
1833                } else if treat_eof_as_epsilon
1834                    && transition.matches_kind(transition_kind, TOKEN_EOF, 1, max_token_type)
1835                {
1836                    scratch.stack.push((
1837                        config.moved_to(transition.target(), config.context, &self.store.contexts),
1838                        collect_predicates,
1839                    ));
1840                }
1841            }
1842        }
1843        #[cfg(feature = "perf-counters")]
1844        crate::perf::record_closure(scratch.visited.len());
1845    }
1846
1847    fn closure_at_rule_stop(
1848        &mut self,
1849        config: AtnConfig,
1850        collect_predicates: bool,
1851        configs: &mut AtnConfigSet,
1852        merge_cache: &mut PredictionWorkspace,
1853        stack: &mut Vec<(AtnConfig, bool)>,
1854    ) -> bool {
1855        if self.store.contexts.is_empty(config.context) {
1856            if configs.full_context() {
1857                configs.add(config, &mut self.store.contexts, merge_cache);
1858                return true;
1859            }
1860            return false;
1861        }
1862        let mut handled_all_paths = true;
1863        for index in 0..self.store.contexts.len(config.context) {
1864            let Some(return_state) = self.store.contexts.return_state(config.context, index) else {
1865                continue;
1866            };
1867            if return_state == EMPTY_RETURN_STATE {
1868                if configs.full_context() {
1869                    let mut empty_context_config = config.clone();
1870                    empty_context_config.set_context(EMPTY_CONTEXT, &self.store.contexts);
1871                    configs.add(empty_context_config, &mut self.store.contexts, merge_cache);
1872                } else {
1873                    handled_all_paths = false;
1874                }
1875                continue;
1876            }
1877            let parent = self
1878                .store
1879                .contexts
1880                .parent(config.context, index)
1881                .unwrap_or(EMPTY_CONTEXT);
1882            let next = config.moved_to(return_state, parent, &self.store.contexts);
1883            stack.push((next, collect_predicates));
1884        }
1885        handled_all_paths
1886    }
1887
1888    #[allow(clippy::too_many_arguments)]
1889    fn epsilon_target_config(
1890        &mut self,
1891        config: &AtnConfig,
1892        transition: ParserTransition<'_>,
1893        transition_kind: ParserTransitionKind,
1894        precedence: i32,
1895        collect_predicates: bool,
1896        full_context: bool,
1897    ) -> Option<AtnConfig> {
1898        let semantic_context = match transition_kind {
1899            ParserTransitionKind::Predicate if collect_predicates => SemanticContext::and(
1900                config.semantic_context.clone(),
1901                SemanticContext::Predicate {
1902                    rule_index: transition.arg0() as usize,
1903                    pred_index: transition.arg1() as usize,
1904                    context_dependent: transition.arg2() != 0,
1905                },
1906            ),
1907            ParserTransitionKind::Precedence
1908                if collect_predicates
1909                    && i32::from_le_bytes(transition.arg0().to_le_bytes()) < precedence =>
1910            {
1911                return None;
1912            }
1913            ParserTransitionKind::Precedence if collect_predicates && !full_context => {
1914                SemanticContext::and(
1915                    config.semantic_context.clone(),
1916                    SemanticContext::Precedence {
1917                        precedence: i32::from_le_bytes(transition.arg0().to_le_bytes()),
1918                    },
1919                )
1920            }
1921            _ => config.semantic_context.clone(),
1922        };
1923        let context = if transition_kind == ParserTransitionKind::Rule {
1924            self.store
1925                .contexts
1926                .singleton(config.context, transition.arg1() as usize)
1927        } else {
1928            config.context
1929        };
1930        let mut target = config.moved_to(transition.target(), context, &self.store.contexts);
1931        target.semantic_context = semantic_context;
1932        Some(target)
1933    }
1934
1935    fn dfa_prediction_info(
1936        &self,
1937        decision: usize,
1938        state_number: DfaStateId,
1939    ) -> Option<DfaPredictionInfo> {
1940        let dfa = self.store.decision_to_dfa.get(decision)?;
1941        let state = dfa.state(state_number)?;
1942        let alt = state.prediction()?;
1943        let requires_full_context = state.requires_full_context();
1944        let conflicting_alts = if requires_full_context {
1945            let stored = dfa.conflicting_alts(state_number);
1946            if stored.is_empty() {
1947                dfa.configs(state_number).alts().into_iter().collect()
1948            } else {
1949                stored.to_vec()
1950            }
1951        } else {
1952            Vec::new()
1953        };
1954        Some(DfaPredictionInfo {
1955            prediction: ParserAtnPrediction {
1956                alt,
1957                requires_full_context,
1958                // Precomputed at accept time (see compute_target_state) so
1959                // warm accept lookup does not rescan the cold config set.
1960                has_semantic_context: state.has_semantic_context(),
1961                diagnostic: None,
1962            },
1963            conflicting_alts,
1964        })
1965    }
1966}
1967
1968/// Reports whether closure should skip the loop-entry branch for a
1969/// left-recursive rule under the current caller context.
1970pub(crate) fn can_drop_left_recursive_loop_entry_edge(
1971    atn: &Atn,
1972    state: AtnState<'_>,
1973    contexts: &ContextArena,
1974    context: ContextId,
1975) -> bool {
1976    if state.kind() != AtnStateKind::StarLoopEntry
1977        || !state.precedence_rule_decision()
1978        || contexts.is_empty(context)
1979        || contexts.has_empty_path(context)
1980    {
1981        return false;
1982    }
1983    let Some(rule_index) = state.rule_index() else {
1984        return false;
1985    };
1986    for index in 0..contexts.len(context) {
1987        let Some(return_state_number) = contexts.return_state(context, index) else {
1988            return false;
1989        };
1990        let Some(return_state) = atn.state(return_state_number) else {
1991            return false;
1992        };
1993        if return_state.rule_index() != Some(rule_index) {
1994            return false;
1995        }
1996    }
1997    let Some(block_end_state_number) = state
1998        .transitions()
1999        .first()
2000        .and_then(|transition| atn.state(transition.target()))
2001        .and_then(AtnState::end_state)
2002    else {
2003        return false;
2004    };
2005    for index in 0..contexts.len(context) {
2006        let return_state_number = contexts
2007            .return_state(context, index)
2008            .expect("return state checked above");
2009        let return_state = atn
2010            .state(return_state_number)
2011            .expect("return state checked above");
2012        if return_state.state_number() == block_end_state_number {
2013            continue;
2014        }
2015        if return_state.transitions().len() != 1
2016            || !return_state
2017                .transitions()
2018                .first()
2019                .is_some_and(ParserTransition::is_epsilon)
2020        {
2021            return false;
2022        }
2023        let return_target = return_state
2024            .transitions()
2025            .first()
2026            .expect("single transition checked above")
2027            .target();
2028        if return_state.kind() == AtnStateKind::BlockEnd && return_target == state.state_number() {
2029            continue;
2030        }
2031        if return_target == block_end_state_number {
2032            continue;
2033        }
2034        let Some(return_target_state) = atn.state(return_target) else {
2035            return false;
2036        };
2037        if return_target_state.kind() == AtnStateKind::BlockEnd
2038            && return_target_state.transitions().len() == 1
2039            && return_target_state
2040                .transitions()
2041                .first()
2042                .is_some_and(ParserTransition::is_epsilon)
2043            && return_target_state
2044                .transitions()
2045                .first()
2046                .is_some_and(|transition| transition.target() == state.state_number())
2047        {
2048            continue;
2049        }
2050        return false;
2051    }
2052    true
2053}
2054
2055fn configs_have_semantic_context_for_alt(configs: &AtnConfigSet, alt: usize) -> bool {
2056    configs
2057        .configs()
2058        .iter()
2059        .any(|config| config.alt == alt && !config.semantic_context.is_none())
2060}
2061
2062#[derive(Clone, Debug, Eq, PartialEq)]
2063pub enum ParserAtnSimulatorError {
2064    MissingAtnState(usize),
2065    MissingDfaState(DfaStateId),
2066    NoViableAlt { symbol: i32, index: usize },
2067    PredictionRequiresMoreLookahead,
2068    UnknownDecision(usize),
2069}
2070
2071/// Java `DFASerializer.getStateString`: `:sN^=>alt` for accept states.
2072fn dfa_state_display(state: ParserDfaStateView<'_>, deferred: bool) -> String {
2073    let mut out = String::new();
2074    let is_accept = state.is_accept_state() && !deferred;
2075    if is_accept {
2076        out.push(':');
2077    }
2078    out.push('s');
2079    out.push_str(&state.id().index().to_string());
2080    if state.requires_full_context() {
2081        out.push('^');
2082    }
2083    if is_accept {
2084        out.push_str("=>");
2085        out.push_str(
2086            &state
2087                .prediction()
2088                .map(|prediction| prediction.to_string())
2089                .unwrap_or_default(),
2090        );
2091    }
2092    out
2093}
2094
2095#[cfg(test)]
2096#[allow(clippy::disallowed_methods)] // `insta` assertion macros unwrap internal I/O.
2097mod tests {
2098    use super::*;
2099    use crate::atn::AtnStateKind;
2100
2101    fn finish_atn(builder: ParserAtnBuilder) -> Atn {
2102        builder.finish().expect("valid packed parser ATN")
2103    }
2104
2105    #[test]
2106    fn union_decision_dfa_preserves_disjoint_coverage() {
2107        fn configs(
2108            atn_state: usize,
2109            arena: &mut ContextArena,
2110            workspace: &mut PredictionWorkspace,
2111        ) -> AtnConfigSet {
2112            let mut set = AtnConfigSet::new();
2113            set.add(
2114                AtnConfig::new(atn_state, 1, EMPTY_CONTEXT, arena),
2115                arena,
2116                workspace,
2117            );
2118            set
2119        }
2120        fn state(
2121            atn_state: usize,
2122            arena: &mut ContextArena,
2123            workspace: &mut PredictionWorkspace,
2124        ) -> DfaStateBuilder {
2125            DfaStateBuilder::new(configs(atn_state, arena, workspace))
2126        }
2127        let mut arena = ContextArena::new();
2128        let mut workspace = PredictionWorkspace::default();
2129
2130        // Two DFAs that evolved independently from the same grammar: equal
2131        // state/edge counts, but disjoint transitions and different state
2132        // numbering for the shared successor.
2133        let mut shared = ParserDfa::with_max_token_type(0, 0, 8);
2134        let shared_root = shared.add_state(state(10, &mut arena, &mut workspace));
2135        let shared_a = shared.add_state(state(11, &mut arena, &mut workspace));
2136        shared.add_edge(shared_root, 1, shared_a);
2137        shared.set_start_state(shared_root);
2138
2139        let mut local = ParserDfa::with_max_token_type(0, 0, 8);
2140        let local_b = local.add_state(state(12, &mut arena, &mut workspace));
2141        let local_root = local.add_state(state(10, &mut arena, &mut workspace));
2142        local.add_edge(local_root, 2, local_b);
2143        local.set_precedence_start_state(3, local_root);
2144
2145        union_decision_dfa(&mut shared, local);
2146
2147        // The root (same config set) gained local's edge without losing its
2148        // own, with the target re-keyed into shared numbering.
2149        assert_eq!(shared.edge(shared_root, 1), Some(shared_a));
2150        let merged_b = shared
2151            .state_id_for_configs(&configs(12, &mut arena, &mut workspace))
2152            .expect("local-only state adopted");
2153        assert_eq!(shared.edge(shared_root, 2), Some(merged_b));
2154        assert_eq!(shared.states().len(), 3);
2155        // Start-state gaps fill from local; incumbents are kept.
2156        assert_eq!(shared.start_state(), Some(shared_root));
2157        assert_eq!(shared.precedence_start_state(3), Some(shared_root));
2158    }
2159
2160    #[test]
2161    fn union_prediction_stores_remaps_context_ids_before_dfa_union() {
2162        let atn = two_token_decision_atn();
2163        let mut shared = PredictionStore::new(&atn);
2164        let mut local = PredictionStore::new(&atn);
2165        let mut workspace = PredictionWorkspace::default();
2166
2167        let distracting = shared.contexts.singleton(EMPTY_CONTEXT, 99);
2168        let local_context = local.contexts.singleton(EMPTY_CONTEXT, 7);
2169        assert_eq!(distracting, local_context, "both stores allocate ID 1");
2170
2171        let mut configs = AtnConfigSet::new();
2172        configs.add(
2173            AtnConfig::new(42, 1, local_context, &local.contexts),
2174            &mut local.contexts,
2175            &mut workspace,
2176        );
2177        local.decision_to_dfa[0].add_state(DfaStateBuilder::new(configs));
2178
2179        union_prediction_stores(&mut shared, local, &mut workspace);
2180
2181        let imported = shared.decision_to_dfa[0]
2182            .states()
2183            .flat_map(|state| shared.decision_to_dfa[0].configs(state.id()).configs())
2184            .find(|config| config.state == 42)
2185            .expect("local DFA config imported");
2186        assert_ne!(imported.context, local_context);
2187        assert_eq!(shared.contexts.return_state(imported.context, 0), Some(7));
2188        imported.assert_store(&shared.contexts);
2189    }
2190
2191    #[test]
2192    fn outer_context_cache_invalidates_with_rule_context_version() {
2193        let atn = two_token_decision_atn();
2194        let mut simulator = ParserAtnSimulator::new(&atn);
2195
2196        let first = simulator.intern_prediction_context(1, [7]);
2197        let cached = simulator.intern_prediction_context(1, [99]);
2198        let refreshed = simulator.intern_prediction_context(2, [99]);
2199
2200        assert_eq!(cached, first);
2201        assert_ne!(refreshed, first);
2202        assert_eq!(
2203            simulator.store.contexts.return_state(refreshed, 0),
2204            Some(99)
2205        );
2206        let stats = simulator.prediction_context_stats();
2207        assert_eq!(stats.outer_context_cache_hits, 1);
2208        assert_eq!(stats.outer_context_cache_misses, 2);
2209    }
2210
2211    #[test]
2212    fn outer_context_cache_is_simulator_local() {
2213        let atn = two_token_decision_atn();
2214        let mut first = ParserAtnSimulator::new(&atn);
2215        let mut second = ParserAtnSimulator::new(&atn);
2216
2217        let first_context = first.intern_prediction_context(1, [7]);
2218        let second_context = second.intern_prediction_context(1, [99]);
2219
2220        assert_eq!(first.store.contexts.return_state(first_context, 0), Some(7));
2221        assert_eq!(
2222            second.store.contexts.return_state(second_context, 0),
2223            Some(99)
2224        );
2225    }
2226
2227    #[test]
2228    fn adaptive_predict_reuses_dense_dfa_edges() {
2229        let atn = two_token_decision_atn();
2230        let mut simulator = ParserAtnSimulator::new(&atn);
2231
2232        assert_eq!(simulator.adaptive_predict(0, [1, 2]), Ok(1));
2233        assert_eq!(simulator.adaptive_predict(0, [1, 3]), Ok(2));
2234
2235        let dfa = &simulator.decision_dfas()[0];
2236        let start = dfa.start_state().expect("start state");
2237        let after_first = dfa.state(start).and_then(|state| state.edge(1));
2238        assert!(after_first.is_some());
2239    }
2240
2241    #[test]
2242    fn shared_simulator_reuses_learned_dfa_states() {
2243        let atn = Box::leak(Box::new(two_token_decision_atn()));
2244        let learned_states = {
2245            let mut simulator = ParserAtnSimulator::new_shared(atn);
2246            assert_eq!(simulator.adaptive_predict(0, [1, 2]), Ok(1));
2247            simulator.decision_dfas()[0].states().len()
2248        };
2249
2250        let simulator = ParserAtnSimulator::new_shared(atn);
2251        assert_eq!(simulator.decision_dfas()[0].states().len(), learned_states);
2252    }
2253
2254    #[test]
2255    fn clear_shared_dfa_drops_learned_states() {
2256        let atn = Box::leak(Box::new(two_token_decision_atn()));
2257        {
2258            let mut simulator = ParserAtnSimulator::new_shared(atn);
2259            assert_eq!(simulator.adaptive_predict(0, [1, 2]), Ok(1));
2260            assert!(!simulator.decision_dfas()[0].is_empty());
2261        }
2262
2263        ParserAtnSimulator::clear_shared_dfa(atn);
2264
2265        let simulator = ParserAtnSimulator::new_shared(atn);
2266        assert!(simulator.decision_dfas()[0].is_empty());
2267    }
2268
2269    #[test]
2270    fn clear_dfa_rejects_stale_overlapping_simulator_publication() {
2271        let atn = Box::leak(Box::new(two_token_decision_atn()));
2272        let mut current = ParserAtnSimulator::new_shared(atn);
2273        let mut stale = ParserAtnSimulator::new_shared(atn);
2274        assert_eq!(stale.adaptive_predict(0, [1, 2]), Ok(1));
2275        assert!(!stale.decision_dfas()[0].is_empty());
2276
2277        current.clear_dfa();
2278        drop(stale);
2279        drop(current);
2280
2281        let simulator = ParserAtnSimulator::new_shared(atn);
2282        assert!(simulator.decision_dfas()[0].is_empty());
2283    }
2284
2285    #[test]
2286    fn adaptive_predict_reports_no_viable_alt() {
2287        let atn = two_token_decision_atn();
2288        let mut simulator = ParserAtnSimulator::new(&atn);
2289
2290        assert_eq!(
2291            simulator.adaptive_predict(0, [4]),
2292            Err(ParserAtnSimulatorError::NoViableAlt {
2293                symbol: 4,
2294                index: 0
2295            })
2296        );
2297    }
2298
2299    #[test]
2300    fn adaptive_predict_marks_sll_conflict_for_full_context() {
2301        let atn = ambiguous_single_token_decision_atn();
2302        let mut simulator = ParserAtnSimulator::new(&atn);
2303
2304        assert_eq!(simulator.adaptive_predict(0, [1]), Ok(1));
2305        let prediction = simulator
2306            .adaptive_predict_info_with_precedence(0, 0, [1])
2307            .expect("prediction");
2308        insta::assert_debug_snapshot!(
2309            "adaptive_predict_marks_sll_conflict_for_full_context",
2310            prediction
2311        );
2312
2313        let dfa = &simulator.decision_dfas()[0];
2314        let start = dfa.start_state().expect("start state");
2315        let target = dfa
2316            .state(start)
2317            .and_then(|state| state.edge(1))
2318            .expect("edge for token 1");
2319        let state = dfa.state(target).expect("target state");
2320        assert!(state.is_accept_state());
2321        assert!(state.requires_full_context());
2322        assert_eq!(state.prediction(), Some(1));
2323    }
2324
2325    #[test]
2326    fn adaptive_predict_keeps_rule_stop_configs_at_eof() {
2327        let atn = optional_token_decision_atn();
2328        let mut simulator = ParserAtnSimulator::new(&atn);
2329
2330        assert_eq!(simulator.adaptive_predict(0, [TOKEN_EOF]), Ok(2));
2331    }
2332
2333    #[test]
2334    fn adaptive_predict_treats_repeated_eof_as_epsilon_after_first_eof() {
2335        let atn = multiple_eof_decision_atn();
2336        let mut simulator = ParserAtnSimulator::new(&atn);
2337
2338        assert_eq!(simulator.adaptive_predict(0, [1, TOKEN_EOF]), Ok(1));
2339    }
2340
2341    #[test]
2342    fn adaptive_predict_uses_finished_entry_rule_alt_on_error_edge() {
2343        let atn = prefix_alt_decision_atn();
2344        let mut simulator = ParserAtnSimulator::new(&atn);
2345
2346        assert_eq!(simulator.adaptive_predict(0, [1, 3]), Ok(1));
2347    }
2348
2349    #[test]
2350    fn adaptive_predict_keeps_prefix_alt_until_longer_alt_finishes() {
2351        let atn = three_token_prefix_alt_decision_atn();
2352        let mut simulator = ParserAtnSimulator::new(&atn);
2353
2354        assert_eq!(simulator.adaptive_predict(0, [1, 2, TOKEN_EOF]), Ok(1));
2355        assert_eq!(simulator.adaptive_predict(0, [1, 2, 1, TOKEN_EOF]), Ok(2));
2356    }
2357
2358    #[test]
2359    fn sll_probe_keeps_unique_alt_early_termination() {
2360        let atn = three_token_prefix_alt_decision_atn();
2361        let mut simulator = ParserAtnSimulator::new(&atn);
2362        let mut input = VecIntStream::new(vec![1, 2, TOKEN_EOF]);
2363
2364        let prediction = simulator
2365            .adaptive_predict_stream_info_sll_probe(0, 0, &mut input)
2366            .expect("SLL prediction should succeed");
2367
2368        assert_eq!(prediction.alt, 2);
2369    }
2370
2371    #[test]
2372    fn adaptive_predict_uses_precedence_dfa_start_states() {
2373        let atn = two_token_decision_atn_with_precedence(true);
2374        let mut simulator = ParserAtnSimulator::new(&atn);
2375
2376        assert_eq!(
2377            simulator.adaptive_predict_with_precedence(0, 3, [1, 2]),
2378            Ok(1)
2379        );
2380        assert_eq!(
2381            simulator.adaptive_predict_with_precedence(0, 7, [1, 3]),
2382            Ok(2)
2383        );
2384
2385        let dfa = &simulator.decision_dfas()[0];
2386        assert!(dfa.is_precedence_dfa());
2387        assert!(dfa.precedence_start_state(3).is_some());
2388        assert!(dfa.precedence_start_state(7).is_some());
2389    }
2390
2391    #[test]
2392    fn adaptive_predict_stream_restores_input_position() {
2393        let atn = two_token_decision_atn();
2394        let mut simulator = ParserAtnSimulator::new(&atn);
2395        let mut input = VecIntStream::new(vec![1, 3, TOKEN_EOF]);
2396
2397        assert_eq!(simulator.adaptive_predict_stream(0, &mut input), Ok(2));
2398        assert_eq!(input.index(), 0);
2399        assert_eq!(input.la(1), 1);
2400    }
2401
2402    #[test]
2403    fn adaptive_predict_stream_retries_full_context_conflict() {
2404        let atn = ambiguous_single_token_decision_atn();
2405        let mut simulator = ParserAtnSimulator::new(&atn);
2406        let mut input = VecIntStream::new(vec![1, TOKEN_EOF]);
2407
2408        let prediction = simulator
2409            .adaptive_predict_stream_info_with_precedence(0, 0, &mut input)
2410            .expect("prediction");
2411
2412        insta::assert_debug_snapshot!(
2413            "adaptive_predict_stream_retries_full_context_conflict",
2414            prediction
2415        );
2416        assert_eq!(input.index(), 0);
2417    }
2418
2419    #[test]
2420    fn full_context_memo_replays_identical_retries() {
2421        let atn = ambiguous_single_token_decision_atn();
2422        let mut simulator = ParserAtnSimulator::new(&atn);
2423
2424        // First occurrence: SLL conflicts, the LL loop runs and its
2425        // resolution is recorded.
2426        let mut input = VecIntStream::new(vec![1, TOKEN_EOF]);
2427        let fresh = simulator
2428            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2429            .expect("fresh prediction");
2430        assert_eq!(simulator.full_context_memo_len, 1);
2431        assert_eq!(input.index(), 0, "cursor restored after prediction");
2432
2433        // Second identical occurrence: the memo replays without running the
2434        // LL loop, producing a byte-identical prediction (diagnostic
2435        // included) and identical cursor behavior.
2436        let replayed = simulator
2437            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2438            .expect("memoized prediction");
2439        assert_eq!(replayed, fresh);
2440        assert_eq!(simulator.full_context_memo_len, 1, "no duplicate entry");
2441        assert_eq!(input.index(), 0);
2442
2443        // A different upcoming token sequence misses the memo: a fresh LL
2444        // run happens (and records its own entry) instead of a stale replay.
2445        let mut other_input = VecIntStream::new(vec![2, TOKEN_EOF]);
2446        let other = simulator.adaptive_predict_stream_info_with_context(
2447            0,
2448            0,
2449            &mut other_input,
2450            EMPTY_CONTEXT,
2451        );
2452        // Token 2 has no viable alternative in this ATN — the memo must not
2453        // have answered for it.
2454        assert!(other.is_err(), "different window must not replay");
2455
2456        // A different outer context misses the memo as well.
2457        let context = simulator.store.contexts.singleton(EMPTY_CONTEXT, 6);
2458        let mut input = VecIntStream::new(vec![1, TOKEN_EOF]);
2459        let _ = simulator
2460            .adaptive_predict_stream_info_with_context(0, 0, &mut input, context)
2461            .expect("prediction under a different context");
2462        assert_eq!(
2463            simulator.full_context_memo_len, 2,
2464            "distinct context records its own entry"
2465        );
2466    }
2467
2468    #[test]
2469    fn full_context_memo_walks_multi_token_windows() {
2470        let atn = ambiguous_three_token_decision_atn();
2471        let mut simulator = ParserAtnSimulator::new(&atn);
2472
2473        // Fresh LL run consumes the three-token window before resolving; the
2474        // recorded entry carries a non-empty window tail.
2475        let mut input = VecIntStream::new(vec![1, 2, 3, TOKEN_EOF]);
2476        let fresh = simulator
2477            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2478            .expect("fresh prediction");
2479        assert_eq!(simulator.full_context_memo_len, 1);
2480        let recorded_window_len = simulator
2481            .full_context_memo
2482            .values()
2483            .next()
2484            .and_then(|entries| entries.first())
2485            .map(|entry| entry.window_tail.len())
2486            .expect("one recorded entry");
2487        assert!(
2488            recorded_window_len >= 1,
2489            "the LL loop consumed tokens, so the window tail must be non-empty"
2490        );
2491
2492        // Identical occurrence replays through the token-for-token compare,
2493        // byte-identical (stop_index recomputed from the live cursor).
2494        let replayed = simulator
2495            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2496            .expect("memoized prediction");
2497        assert_eq!(replayed, fresh);
2498        assert_eq!(input.index(), 0, "cursor restored by the caller wrapper");
2499
2500        // Same first symbol, diverging mid-window: the compare must reject
2501        // the entry and restore the cursor to the decision start before the
2502        // fresh LL run happens. Token 9 has no viable alternative, so a
2503        // (wrong) replay would have returned Ok — the Err proves the miss;
2504        // the memo also records nothing for the failed occurrence.
2505        let mut diverging = VecIntStream::new(vec![1, 9, 9, TOKEN_EOF]);
2506        let result = simulator.adaptive_predict_stream_info_with_context(
2507            0,
2508            0,
2509            &mut diverging,
2510            EMPTY_CONTEXT,
2511        );
2512        assert!(result.is_err(), "mid-window divergence must not replay");
2513        assert_eq!(simulator.full_context_memo_len, 1);
2514    }
2515
2516    #[test]
2517    fn full_context_memo_stays_off_for_predicated_atns_and_exact_mode() {
2518        // Exact-ambiguity detection changes how far the LL loop consumes, so
2519        // the memo must not record or replay in that mode.
2520        let atn = ambiguous_single_token_decision_atn();
2521        let mut simulator = ParserAtnSimulator::new(&atn);
2522        simulator.set_exact_ambig_detection(true);
2523        let mut input = VecIntStream::new(vec![1, TOKEN_EOF]);
2524        let _ = simulator
2525            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2526            .expect("prediction");
2527        assert_eq!(simulator.full_context_memo_len, 0);
2528
2529        // Predicates make outcomes depend on caller-side evaluation: any
2530        // semantic transition in the ATN disables the memo entirely.
2531        let mut atn = ParserAtnBuilder::new(1);
2532        add_state(&mut atn, 0, AtnStateKind::Basic);
2533        add_state(&mut atn, 1, AtnStateKind::Basic);
2534        atn.add_transition(
2535            0,
2536            ParserTransitionSpec::Predicate {
2537                target: 1,
2538                rule_index: 0,
2539                pred_index: 0,
2540                context_dependent: false,
2541            },
2542        )
2543        .expect("transition");
2544        atn.set_rule_to_start_state(vec![0])
2545            .expect("rule start states");
2546        atn.set_rule_to_stop_state(vec![1])
2547            .expect("rule stop states");
2548        let atn = finish_atn(atn);
2549        let mut simulator = ParserAtnSimulator::new(&atn);
2550        assert!(!simulator.full_context_memo_allowed());
2551    }
2552
2553    #[test]
2554    fn full_context_memo_allows_action_and_precedence_transitions() {
2555        // Actions never affect prediction (upstream ActionTransition is
2556        // epsilon for analysis), and precedence transitions resolve against
2557        // the precedence already in the memo key — neither disables the memo.
2558        // Gating on them would turn the memo off for every grammar with a
2559        // left-recursive rule.
2560        let mut atn = ParserAtnBuilder::new(1);
2561        add_state(&mut atn, 0, AtnStateKind::Basic);
2562        add_state(&mut atn, 1, AtnStateKind::Basic);
2563        add_state(&mut atn, 2, AtnStateKind::Basic);
2564        atn.add_transition(
2565            0,
2566            ParserTransitionSpec::Action {
2567                target: 1,
2568                rule_index: 0,
2569                action_index: Some(0),
2570                context_dependent: false,
2571            },
2572        )
2573        .expect("transition");
2574        atn.add_transition(
2575            1,
2576            ParserTransitionSpec::Precedence {
2577                target: 2,
2578                precedence: 1,
2579            },
2580        )
2581        .expect("transition");
2582        atn.set_rule_to_start_state(vec![0])
2583            .expect("rule start states");
2584        atn.set_rule_to_stop_state(vec![2])
2585            .expect("rule stop states");
2586        let atn = finish_atn(atn);
2587        let mut simulator = ParserAtnSimulator::new(&atn);
2588        assert!(simulator.full_context_memo_allowed());
2589    }
2590
2591    #[test]
2592    fn context_prediction_reports_context_sensitivity_for_dfa_conflict() {
2593        let atn = two_token_decision_atn();
2594        let mut simulator = ParserAtnSimulator::new(&atn);
2595        let mut workspace = PredictionWorkspace::default();
2596        let mut start_configs = AtnConfigSet::new();
2597        start_configs.add(
2598            AtnConfig::new(2, 1, EMPTY_CONTEXT, &simulator.store.contexts),
2599            &mut simulator.store.contexts,
2600            &mut workspace,
2601        );
2602        let start =
2603            simulator.store.decision_to_dfa[0].add_state(DfaStateBuilder::new(start_configs));
2604        simulator.store.decision_to_dfa[0].set_start_state(start);
2605
2606        let mut accept_configs = AtnConfigSet::new();
2607        accept_configs.add(
2608            AtnConfig::new(3, 1, EMPTY_CONTEXT, &simulator.store.contexts).with_semantic_context(
2609                SemanticContext::Predicate {
2610                    rule_index: 0,
2611                    pred_index: 0,
2612                    context_dependent: false,
2613                },
2614            ),
2615            &mut simulator.store.contexts,
2616            &mut workspace,
2617        );
2618        let mut accept_state = DfaStateBuilder::new(accept_configs);
2619        accept_state.mark_accept(1);
2620        accept_state.set_requires_full_context(true);
2621        accept_state.set_conflicting_alts(vec![1, 2]);
2622        let accept = simulator.store.decision_to_dfa[0].add_state(accept_state);
2623        simulator.store.decision_to_dfa[0].add_edge(start, 1, accept);
2624
2625        let mut input = VecIntStream::new(vec![1, 3, TOKEN_EOF]);
2626        let prediction = simulator
2627            .adaptive_predict_stream_info_with_context(0, 0, &mut input, EMPTY_CONTEXT)
2628            .expect("prediction");
2629
2630        insta::assert_debug_snapshot!(
2631            "context_prediction_reports_context_sensitivity_for_dfa_conflict",
2632            prediction
2633        );
2634        assert_eq!(input.index(), 0);
2635    }
2636
2637    #[test]
2638    fn full_context_reach_prefers_longer_match_over_skipped_stop_state() {
2639        let atn = prefix_alt_decision_atn();
2640        let mut simulator = ParserAtnSimulator::new(&atn);
2641        let mut configs = AtnConfigSet::new_full_context(true);
2642        let mut merge_cache = PredictionWorkspace::default();
2643        configs.add(
2644            AtnConfig::new(2, 1, EMPTY_CONTEXT, &simulator.store.contexts),
2645            &mut simulator.store.contexts,
2646            &mut merge_cache,
2647        );
2648        configs.add(
2649            AtnConfig::new(1, 2, EMPTY_CONTEXT, &simulator.store.contexts),
2650            &mut simulator.store.contexts,
2651            &mut merge_cache,
2652        );
2653
2654        let reach = simulator.compute_reach_set(&configs, 2, true, 0, &mut merge_cache);
2655
2656        assert_eq!(reach.alts(), std::iter::once(2).collect());
2657        assert!(simulator.configs_all_reached_rule_stop(&reach));
2658    }
2659
2660    #[test]
2661    fn sll_closure_follows_empty_context_rule_stop_exits() {
2662        let mut atn = ParserAtnBuilder::new(1);
2663        add_state(&mut atn, 0, AtnStateKind::RuleStop);
2664        add_state(&mut atn, 1, AtnStateKind::Basic);
2665        add_state(&mut atn, 2, AtnStateKind::Basic);
2666        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
2667            .expect("transition");
2668        atn.add_transition(
2669            1,
2670            ParserTransitionSpec::Atom {
2671                target: 2,
2672                label: 1,
2673            },
2674        )
2675        .expect("transition");
2676        atn.set_rule_to_start_state(vec![0])
2677            .expect("rule start states");
2678        atn.set_rule_to_stop_state(vec![0])
2679            .expect("rule stop states");
2680        let atn = finish_atn(atn);
2681
2682        let mut simulator = ParserAtnSimulator::new(&atn);
2683        let mut configs = AtnConfigSet::new_full_context(false);
2684        let mut merge_cache = PredictionWorkspace::default();
2685        let mut scratch = ClosureScratch::default();
2686        let config = AtnConfig::new(0, 2, EMPTY_CONTEXT, &simulator.store.contexts);
2687        simulator.closure(
2688            config,
2689            &mut configs,
2690            &mut merge_cache,
2691            &mut scratch,
2692            ClosureParams {
2693                precedence: 0,
2694                collect_predicates: true,
2695                treat_eof_as_epsilon: false,
2696            },
2697        );
2698
2699        assert_eq!(configs.len(), 1);
2700        let config = &configs.configs()[0];
2701        assert_eq!(config.state, 1);
2702        assert_eq!(config.alt, 2);
2703        assert_eq!(config.reaches_into_outer_context, 1);
2704    }
2705
2706    #[test]
2707    fn precedence_contexts_are_collected_only_for_start_closure() {
2708        let mut atn = ParserAtnBuilder::new(1);
2709        add_state(&mut atn, 0, AtnStateKind::Basic);
2710        add_state(&mut atn, 1, AtnStateKind::Basic);
2711        atn.set_rule_to_start_state(vec![0])
2712            .expect("rule start states");
2713        atn.set_rule_to_stop_state(vec![1])
2714            .expect("rule stop states");
2715        atn.add_transition(
2716            0,
2717            ParserTransitionSpec::Precedence {
2718                target: 1,
2719                precedence: 2,
2720            },
2721        )
2722        .expect("precedence transition");
2723        let atn = finish_atn(atn);
2724        let transition = atn
2725            .state(0)
2726            .expect("source state")
2727            .transitions()
2728            .first()
2729            .expect("precedence transition");
2730        let mut simulator = ParserAtnSimulator::new(&atn);
2731        let config = AtnConfig::new(0, 1, EMPTY_CONTEXT, &simulator.store.contexts);
2732
2733        let sll_start = simulator
2734            .epsilon_target_config(&config, transition, transition.kind(), 1, true, false)
2735            .expect("sll start transition");
2736        assert!(matches!(
2737            sll_start.semantic_context,
2738            SemanticContext::Precedence { precedence: 2 }
2739        ));
2740
2741        let full_context_start = simulator
2742            .epsilon_target_config(&config, transition, transition.kind(), 1, true, true)
2743            .expect("full-context start transition");
2744        assert!(full_context_start.semantic_context.is_none());
2745
2746        let reach = simulator
2747            .epsilon_target_config(&config, transition, transition.kind(), 3, false, false)
2748            .expect("reach transition");
2749        assert!(reach.semantic_context.is_none());
2750
2751        assert!(
2752            simulator
2753                .epsilon_target_config(&config, transition, transition.kind(), 3, true, false)
2754                .is_none()
2755        );
2756    }
2757
2758    #[test]
2759    fn closure_stops_collecting_predicates_after_action_edge() {
2760        // ANTLR's `closure_` sets
2761        // `continueCollecting = collectPredicates && !ActionTransition`, so a
2762        // predicate reached *after* an action edge is NOT folded into the
2763        // config's semantic context — it is deferred to parse time (the
2764        // "action hides predicates" rule). Build `0 -Action-> 1 -Pred-> 2` and
2765        // assert the closure config carries NO semantic context.
2766        let mut atn = ParserAtnBuilder::new(1);
2767        add_state(&mut atn, 0, AtnStateKind::Basic);
2768        add_state(&mut atn, 1, AtnStateKind::Basic);
2769        add_state(&mut atn, 2, AtnStateKind::Basic);
2770        add_state(&mut atn, 3, AtnStateKind::Basic);
2771        atn.add_transition(
2772            0,
2773            ParserTransitionSpec::Action {
2774                target: 1,
2775                rule_index: 0,
2776                action_index: Some(0),
2777                context_dependent: false,
2778            },
2779        )
2780        .expect("transition");
2781        atn.add_transition(
2782            1,
2783            ParserTransitionSpec::Predicate {
2784                target: 2,
2785                rule_index: 0,
2786                pred_index: 0,
2787                context_dependent: false,
2788            },
2789        )
2790        .expect("transition");
2791        atn.add_transition(
2792            2,
2793            ParserTransitionSpec::Atom {
2794                target: 3,
2795                label: 1,
2796            },
2797        )
2798        .expect("transition");
2799        atn.set_rule_to_start_state(vec![0])
2800            .expect("rule start states");
2801        atn.set_rule_to_stop_state(vec![3])
2802            .expect("rule stop states");
2803        let atn = finish_atn(atn);
2804
2805        let mut simulator = ParserAtnSimulator::new(&atn);
2806        let mut configs = AtnConfigSet::new();
2807        let mut merge_cache = PredictionWorkspace::default();
2808        let mut scratch = ClosureScratch::default();
2809        let config = AtnConfig::new(0, 1, EMPTY_CONTEXT, &simulator.store.contexts);
2810        simulator.closure(
2811            config,
2812            &mut configs,
2813            &mut merge_cache,
2814            &mut scratch,
2815            ClosureParams {
2816                precedence: 0,
2817                collect_predicates: true,
2818                treat_eof_as_epsilon: false,
2819            },
2820        );
2821
2822        // The config that stops at state 2 (post-predicate, awaiting the atom)
2823        // must NOT carry the predicate — the action edge turned collection off.
2824        let at_two = configs
2825            .configs()
2826            .iter()
2827            .find(|config| config.state == 2)
2828            .expect("config at state 2");
2829        assert!(
2830            at_two.semantic_context.is_none(),
2831            "predicate after an action edge must not be collected during prediction"
2832        );
2833
2834        // Control: the SAME predicate reached WITHOUT an intervening action edge
2835        // IS collected (so the assertion above is about the action edge, not a
2836        // blanket failure to collect predicates).
2837        let direct_config = AtnConfig::new(1, 1, EMPTY_CONTEXT, &simulator.store.contexts);
2838        let direct_transition = atn
2839            .state(1)
2840            .expect("predicate source")
2841            .transitions()
2842            .first()
2843            .expect("predicate transition");
2844        let direct = simulator
2845            .epsilon_target_config(
2846                &direct_config,
2847                direct_transition,
2848                direct_transition.kind(),
2849                0,
2850                true,
2851                false,
2852            )
2853            .expect("predicate transition");
2854        assert!(matches!(
2855            direct.semantic_context,
2856            SemanticContext::Predicate { pred_index: 0, .. }
2857        ));
2858    }
2859
2860    #[test]
2861    fn reach_set_skips_closure_for_unique_intermediate_alt() {
2862        let mut atn = ParserAtnBuilder::new(1);
2863        add_state(&mut atn, 0, AtnStateKind::Basic);
2864        add_state(&mut atn, 1, AtnStateKind::Basic);
2865        add_state(&mut atn, 2, AtnStateKind::Basic);
2866        atn.add_transition(
2867            0,
2868            ParserTransitionSpec::Atom {
2869                target: 1,
2870                label: 7,
2871            },
2872        )
2873        .expect("transition");
2874        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
2875            .expect("transition");
2876        atn.set_rule_to_start_state(vec![0])
2877            .expect("rule start states");
2878        atn.set_rule_to_stop_state(vec![2])
2879            .expect("rule stop states");
2880        let atn = finish_atn(atn);
2881
2882        let mut simulator = ParserAtnSimulator::new(&atn);
2883        let mut configs = AtnConfigSet::new_full_context(false);
2884        let mut merge_cache = PredictionWorkspace::default();
2885        configs.add(
2886            AtnConfig::new(0, 1, EMPTY_CONTEXT, &simulator.store.contexts),
2887            &mut simulator.store.contexts,
2888            &mut merge_cache,
2889        );
2890
2891        let reach = simulator.compute_reach_set(&configs, 7, false, 0, &mut merge_cache);
2892
2893        assert_eq!(reach.len(), 1);
2894        assert_eq!(reach.configs()[0].state, 1);
2895    }
2896
2897    #[test]
2898    fn semantic_context_flag_is_scoped_to_predicted_alt() {
2899        let mut arena = ContextArena::new();
2900        let mut workspace = PredictionWorkspace::default();
2901        let mut configs = AtnConfigSet::new();
2902        configs.add(
2903            AtnConfig::new(1, 1, EMPTY_CONTEXT, &arena),
2904            &mut arena,
2905            &mut workspace,
2906        );
2907        configs.add(
2908            AtnConfig::new(2, 2, EMPTY_CONTEXT, &arena).with_semantic_context(
2909                SemanticContext::Predicate {
2910                    rule_index: 0,
2911                    pred_index: 0,
2912                    context_dependent: false,
2913                },
2914            ),
2915            &mut arena,
2916            &mut workspace,
2917        );
2918
2919        assert!(!configs_have_semantic_context_for_alt(&configs, 1));
2920        assert!(configs_have_semantic_context_for_alt(&configs, 2));
2921    }
2922
2923    #[test]
2924    fn adaptive_predict_prefers_non_greedy_exit_before_consuming() {
2925        let atn = non_greedy_optional_exit_first_atn();
2926        let mut simulator = ParserAtnSimulator::new(&atn);
2927
2928        assert_eq!(simulator.adaptive_predict(0, [1, TOKEN_EOF]), Ok(1));
2929    }
2930
2931    #[test]
2932    fn left_recursive_loop_entry_drop_requires_same_rule_return() {
2933        let atn = left_recursive_loop_entry_atn();
2934        let loop_entry = atn.state(1).expect("loop entry");
2935        let mut contexts = ContextArena::new();
2936        let same_rule_context = contexts.singleton(EMPTY_CONTEXT, 4);
2937        let other_rule_context = contexts.singleton(EMPTY_CONTEXT, 5);
2938
2939        assert!(can_drop_left_recursive_loop_entry_edge(
2940            &atn,
2941            loop_entry,
2942            &contexts,
2943            same_rule_context
2944        ));
2945        assert!(!can_drop_left_recursive_loop_entry_edge(
2946            &atn,
2947            loop_entry,
2948            &contexts,
2949            other_rule_context
2950        ));
2951        assert!(!can_drop_left_recursive_loop_entry_edge(
2952            &atn,
2953            loop_entry,
2954            &contexts,
2955            EMPTY_CONTEXT
2956        ));
2957    }
2958
2959    fn two_token_decision_atn() -> Atn {
2960        two_token_decision_atn_with_precedence(false)
2961    }
2962
2963    fn two_token_decision_atn_with_precedence(precedence: bool) -> Atn {
2964        let mut atn = ParserAtnBuilder::new(3);
2965        add_state(&mut atn, 0, AtnStateKind::RuleStart);
2966        add_state(&mut atn, 1, AtnStateKind::BlockStart);
2967        add_state(&mut atn, 2, AtnStateKind::Basic);
2968        add_state(&mut atn, 3, AtnStateKind::Basic);
2969        add_state(&mut atn, 4, AtnStateKind::Basic);
2970        add_state(&mut atn, 5, AtnStateKind::Basic);
2971        add_state(&mut atn, 6, AtnStateKind::BlockEnd);
2972        add_state(&mut atn, 7, AtnStateKind::RuleStop);
2973        atn.set_rule_to_start_state(vec![0])
2974            .expect("rule start states");
2975        atn.set_rule_to_stop_state(vec![7])
2976            .expect("rule stop states");
2977        atn.add_decision_state(1).expect("decision state");
2978        if precedence {
2979            atn.set_precedence_rule_decision(1)
2980                .expect("precedence decision state");
2981        }
2982        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
2983            .expect("transition");
2984        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
2985            .expect("transition");
2986        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
2987            .expect("transition");
2988        atn.add_transition(
2989            2,
2990            ParserTransitionSpec::Atom {
2991                target: 3,
2992                label: 1,
2993            },
2994        )
2995        .expect("transition");
2996        atn.add_transition(
2997            3,
2998            ParserTransitionSpec::Atom {
2999                target: 6,
3000                label: 2,
3001            },
3002        )
3003        .expect("transition");
3004        atn.add_transition(
3005            4,
3006            ParserTransitionSpec::Atom {
3007                target: 5,
3008                label: 1,
3009            },
3010        )
3011        .expect("transition");
3012        atn.add_transition(
3013            5,
3014            ParserTransitionSpec::Atom {
3015                target: 6,
3016                label: 3,
3017            },
3018        )
3019        .expect("transition");
3020        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
3021            .expect("transition");
3022        finish_atn(atn)
3023    }
3024
3025    fn optional_token_decision_atn() -> Atn {
3026        let mut atn = ParserAtnBuilder::new(1);
3027        add_state(&mut atn, 0, AtnStateKind::RuleStart);
3028        add_state(&mut atn, 1, AtnStateKind::BlockStart);
3029        add_state(&mut atn, 2, AtnStateKind::Basic);
3030        add_state(&mut atn, 3, AtnStateKind::BlockEnd);
3031        add_state(&mut atn, 4, AtnStateKind::RuleStop);
3032        atn.set_rule_to_start_state(vec![0])
3033            .expect("rule start states");
3034        atn.set_rule_to_stop_state(vec![4])
3035            .expect("rule stop states");
3036        atn.add_decision_state(1).expect("decision state");
3037        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3038            .expect("transition");
3039        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3040            .expect("transition");
3041        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
3042            .expect("transition");
3043        atn.add_transition(
3044            2,
3045            ParserTransitionSpec::Atom {
3046                target: 3,
3047                label: 1,
3048            },
3049        )
3050        .expect("transition");
3051        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 4 })
3052            .expect("transition");
3053        finish_atn(atn)
3054    }
3055
3056    fn non_greedy_optional_exit_first_atn() -> Atn {
3057        let mut atn = ParserAtnBuilder::new(1);
3058        add_state(&mut atn, 0, AtnStateKind::RuleStart);
3059        add_state(&mut atn, 1, AtnStateKind::BlockStart);
3060        add_state(&mut atn, 2, AtnStateKind::BlockEnd);
3061        add_state(&mut atn, 3, AtnStateKind::Basic);
3062        add_state(&mut atn, 4, AtnStateKind::RuleStop);
3063        atn.set_rule_to_start_state(vec![0])
3064            .expect("rule start states");
3065        atn.set_rule_to_stop_state(vec![4])
3066            .expect("rule stop states");
3067        atn.add_decision_state(1).expect("decision state");
3068        atn.set_non_greedy(1).expect("non-greedy state");
3069        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3070            .expect("transition");
3071        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3072            .expect("transition");
3073        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 3 })
3074            .expect("transition");
3075        atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 4 })
3076            .expect("transition");
3077        atn.add_transition(
3078            3,
3079            ParserTransitionSpec::Atom {
3080                target: 4,
3081                label: 1,
3082            },
3083        )
3084        .expect("transition");
3085        finish_atn(atn)
3086    }
3087
3088    /// `s : A B C | A B C ;` — both alternatives match the same THREE-token
3089    /// sequence, so the SLL conflict's full-context retry consumes multiple
3090    /// tokens before resolving, exercising the memo's window walk (record and
3091    /// probe) rather than the empty-window fast case.
3092    fn ambiguous_three_token_decision_atn() -> Atn {
3093        let mut atn = ParserAtnBuilder::new(3);
3094        add_state(&mut atn, 0, AtnStateKind::RuleStart);
3095        add_state(&mut atn, 1, AtnStateKind::BlockStart);
3096        // Alternative 1: states 2 -A-> 3 -B-> 4 -C-> 5
3097        add_state(&mut atn, 2, AtnStateKind::Basic);
3098        add_state(&mut atn, 3, AtnStateKind::Basic);
3099        add_state(&mut atn, 4, AtnStateKind::Basic);
3100        add_state(&mut atn, 5, AtnStateKind::Basic);
3101        // Alternative 2: states 6 -A-> 7 -B-> 8 -C-> 9
3102        add_state(&mut atn, 6, AtnStateKind::Basic);
3103        add_state(&mut atn, 7, AtnStateKind::Basic);
3104        add_state(&mut atn, 8, AtnStateKind::Basic);
3105        add_state(&mut atn, 9, AtnStateKind::Basic);
3106        add_state(&mut atn, 10, AtnStateKind::BlockEnd);
3107        add_state(&mut atn, 11, AtnStateKind::RuleStop);
3108        atn.set_rule_to_start_state(vec![0])
3109            .expect("rule start states");
3110        atn.set_rule_to_stop_state(vec![11])
3111            .expect("rule stop states");
3112        atn.add_decision_state(1).expect("decision state");
3113        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3114            .expect("transition");
3115        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3116            .expect("transition");
3117        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
3118            .expect("transition");
3119        for (source, target, label) in [
3120            (2, 3, 1),
3121            (3, 4, 2),
3122            (4, 5, 3),
3123            (6, 7, 1),
3124            (7, 8, 2),
3125            (8, 9, 3),
3126        ] {
3127            atn.add_transition(source, ParserTransitionSpec::Atom { target, label })
3128                .expect("transition");
3129        }
3130        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 10 })
3131            .expect("transition");
3132        atn.add_transition(9, ParserTransitionSpec::Epsilon { target: 10 })
3133            .expect("transition");
3134        atn.add_transition(10, ParserTransitionSpec::Epsilon { target: 11 })
3135            .expect("transition");
3136        finish_atn(atn)
3137    }
3138
3139    fn ambiguous_single_token_decision_atn() -> Atn {
3140        let mut atn = ParserAtnBuilder::new(1);
3141        add_state(&mut atn, 0, AtnStateKind::RuleStart);
3142        add_state(&mut atn, 1, AtnStateKind::BlockStart);
3143        add_state(&mut atn, 2, AtnStateKind::Basic);
3144        add_state(&mut atn, 3, AtnStateKind::Basic);
3145        add_state(&mut atn, 4, AtnStateKind::Basic);
3146        add_state(&mut atn, 5, AtnStateKind::Basic);
3147        add_state(&mut atn, 6, AtnStateKind::BlockEnd);
3148        add_state(&mut atn, 7, AtnStateKind::RuleStop);
3149        atn.set_rule_to_start_state(vec![0])
3150            .expect("rule start states");
3151        atn.set_rule_to_stop_state(vec![7])
3152            .expect("rule stop states");
3153        atn.add_decision_state(1).expect("decision state");
3154        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3155            .expect("transition");
3156        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3157            .expect("transition");
3158        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
3159            .expect("transition");
3160        atn.add_transition(
3161            2,
3162            ParserTransitionSpec::Atom {
3163                target: 3,
3164                label: 1,
3165            },
3166        )
3167        .expect("transition");
3168        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 6 })
3169            .expect("transition");
3170        atn.add_transition(
3171            4,
3172            ParserTransitionSpec::Atom {
3173                target: 5,
3174                label: 1,
3175            },
3176        )
3177        .expect("transition");
3178        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
3179            .expect("transition");
3180        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
3181            .expect("transition");
3182        finish_atn(atn)
3183    }
3184
3185    fn prefix_alt_decision_atn() -> Atn {
3186        let mut atn = ParserAtnBuilder::new(3);
3187        add_state(&mut atn, 0, AtnStateKind::BlockStart);
3188        add_state(&mut atn, 1, AtnStateKind::Basic);
3189        add_state(&mut atn, 2, AtnStateKind::RuleStop);
3190        atn.set_rule_to_start_state(vec![0])
3191            .expect("rule start states");
3192        atn.set_rule_to_stop_state(vec![2])
3193            .expect("rule stop states");
3194        atn.add_decision_state(0).expect("decision state");
3195        atn.add_transition(
3196            0,
3197            ParserTransitionSpec::Atom {
3198                target: 2,
3199                label: 1,
3200            },
3201        )
3202        .expect("transition");
3203        atn.add_transition(
3204            0,
3205            ParserTransitionSpec::Atom {
3206                target: 1,
3207                label: 1,
3208            },
3209        )
3210        .expect("transition");
3211        atn.add_transition(
3212            1,
3213            ParserTransitionSpec::Atom {
3214                target: 2,
3215                label: 2,
3216            },
3217        )
3218        .expect("transition");
3219        finish_atn(atn)
3220    }
3221
3222    fn three_token_prefix_alt_decision_atn() -> Atn {
3223        let mut atn = ParserAtnBuilder::new(2);
3224        for (state_number, kind) in [
3225            (0, AtnStateKind::BlockStart),
3226            (1, AtnStateKind::Basic),
3227            (2, AtnStateKind::Basic),
3228            (3, AtnStateKind::Basic),
3229            (4, AtnStateKind::Basic),
3230            (5, AtnStateKind::Basic),
3231            (6, AtnStateKind::RuleStop),
3232        ] {
3233            add_state(&mut atn, state_number, kind);
3234        }
3235        atn.set_rule_to_start_state(vec![0])
3236            .expect("rule start states");
3237        atn.set_rule_to_stop_state(vec![6])
3238            .expect("rule stop states");
3239        atn.add_decision_state(0).expect("decision state");
3240        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3241            .expect("transition");
3242        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 2 })
3243            .expect("transition");
3244        atn.add_transition(
3245            1,
3246            ParserTransitionSpec::Atom {
3247                target: 6,
3248                label: 1,
3249            },
3250        )
3251        .expect("transition");
3252        atn.add_transition(
3253            2,
3254            ParserTransitionSpec::Atom {
3255                target: 3,
3256                label: 1,
3257            },
3258        )
3259        .expect("transition");
3260        atn.add_transition(
3261            3,
3262            ParserTransitionSpec::Atom {
3263                target: 4,
3264                label: 2,
3265            },
3266        )
3267        .expect("transition");
3268        atn.add_transition(
3269            4,
3270            ParserTransitionSpec::Atom {
3271                target: 5,
3272                label: 1,
3273            },
3274        )
3275        .expect("transition");
3276        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
3277            .expect("transition");
3278        finish_atn(atn)
3279    }
3280
3281    fn multiple_eof_decision_atn() -> Atn {
3282        let mut atn = ParserAtnBuilder::new(2);
3283        for state_number in 0..=10 {
3284            let kind = match state_number {
3285                0 => AtnStateKind::RuleStart,
3286                1 => AtnStateKind::BlockStart,
3287                7 => AtnStateKind::BlockEnd,
3288                10 => AtnStateKind::RuleStop,
3289                _ => AtnStateKind::Basic,
3290            };
3291            add_state(&mut atn, state_number, kind);
3292        }
3293        atn.set_rule_to_start_state(vec![0])
3294            .expect("rule start states");
3295        atn.set_rule_to_stop_state(vec![10])
3296            .expect("rule stop states");
3297        atn.add_decision_state(1).expect("decision state");
3298        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
3299            .expect("transition");
3300        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3301            .expect("transition");
3302        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
3303            .expect("transition");
3304        atn.add_transition(
3305            2,
3306            ParserTransitionSpec::Atom {
3307                target: 3,
3308                label: 1,
3309            },
3310        )
3311        .expect("transition");
3312        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 7 })
3313            .expect("transition");
3314        atn.add_transition(
3315            4,
3316            ParserTransitionSpec::Atom {
3317                target: 5,
3318                label: 1,
3319            },
3320        )
3321        .expect("transition");
3322        atn.add_transition(
3323            5,
3324            ParserTransitionSpec::Atom {
3325                target: 6,
3326                label: 2,
3327            },
3328        )
3329        .expect("transition");
3330        atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 7 })
3331            .expect("transition");
3332        atn.add_transition(7, ParserTransitionSpec::Epsilon { target: 8 })
3333            .expect("transition");
3334        atn.add_transition(
3335            8,
3336            ParserTransitionSpec::Atom {
3337                target: 9,
3338                label: TOKEN_EOF,
3339            },
3340        )
3341        .expect("transition");
3342        atn.add_transition(
3343            9,
3344            ParserTransitionSpec::Atom {
3345                target: 10,
3346                label: TOKEN_EOF,
3347            },
3348        )
3349        .expect("transition");
3350        finish_atn(atn)
3351    }
3352
3353    fn left_recursive_loop_entry_atn() -> Atn {
3354        let mut atn = ParserAtnBuilder::new(1);
3355        add_state(&mut atn, 0, AtnStateKind::RuleStart);
3356        add_state(&mut atn, 1, AtnStateKind::StarLoopEntry);
3357        add_state(&mut atn, 2, AtnStateKind::BlockStart);
3358        add_state(&mut atn, 3, AtnStateKind::BlockEnd);
3359        add_state(&mut atn, 4, AtnStateKind::Basic);
3360        assert_eq!(
3361            atn.add_state(AtnStateKind::Basic, Some(1))
3362                .expect("state")
3363                .index(),
3364            5
3365        );
3366        add_state(&mut atn, 6, AtnStateKind::LoopEnd);
3367        add_state(&mut atn, 7, AtnStateKind::RuleStop);
3368        atn.set_rule_to_start_state(vec![0, 5])
3369            .expect("rule start states");
3370        atn.set_rule_to_stop_state(vec![7, 7])
3371            .expect("rule stop states");
3372        atn.set_precedence_rule_decision(1)
3373            .expect("precedence decision state");
3374        atn.set_end_state(2, 3).expect("block end state");
3375        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
3376            .expect("transition");
3377        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 6 })
3378            .expect("transition");
3379        atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 3 })
3380            .expect("transition");
3381        atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 3 })
3382            .expect("transition");
3383        finish_atn(atn)
3384    }
3385
3386    fn add_state(atn: &mut ParserAtnBuilder, state_number: usize, kind: AtnStateKind) {
3387        assert_eq!(
3388            atn.add_state(kind, Some(0)).expect("state").index(),
3389            state_number
3390        );
3391    }
3392
3393    #[derive(Debug)]
3394    struct VecIntStream {
3395        symbols: Vec<i32>,
3396        index: usize,
3397    }
3398
3399    impl VecIntStream {
3400        fn new(symbols: Vec<i32>) -> Self {
3401            Self { symbols, index: 0 }
3402        }
3403    }
3404
3405    impl IntStream for VecIntStream {
3406        fn consume(&mut self) {
3407            if self.la(1) != TOKEN_EOF {
3408                self.index += 1;
3409            }
3410        }
3411
3412        fn la(&mut self, offset: isize) -> i32 {
3413            if offset <= 0 {
3414                return 0;
3415            }
3416            let offset = offset.cast_unsigned() - 1;
3417            self.symbols
3418                .get(self.index + offset)
3419                .copied()
3420                .unwrap_or(TOKEN_EOF)
3421        }
3422
3423        fn index(&self) -> usize {
3424            self.index
3425        }
3426
3427        fn seek(&mut self, index: usize) {
3428            self.index = index;
3429        }
3430
3431        fn size(&self) -> usize {
3432            self.symbols.len()
3433        }
3434    }
3435}