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