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