Skip to main content

antlr4_runtime/
prediction.rs

1use std::rc::Rc;
2
3pub const EMPTY_RETURN_STATE: usize = usize::MAX;
4
5#[derive(Clone, Debug, Eq, Hash, PartialEq)]
6pub enum PredictionContext {
7    Empty,
8    Singleton {
9        parent: Rc<Self>,
10        return_state: usize,
11    },
12    Array {
13        parents: Vec<Rc<Self>>,
14        return_states: Vec<usize>,
15    },
16}
17
18impl PredictionContext {
19    pub fn empty() -> Rc<Self> {
20        Rc::new(Self::Empty)
21    }
22
23    pub fn singleton(parent: Rc<Self>, return_state: usize) -> Rc<Self> {
24        if return_state == EMPTY_RETURN_STATE {
25            Self::empty()
26        } else {
27            Rc::new(Self::Singleton {
28                parent,
29                return_state,
30            })
31        }
32    }
33
34    pub const fn len(&self) -> usize {
35        match self {
36            Self::Empty => 1,
37            Self::Singleton { .. } => 1,
38            Self::Array { return_states, .. } => return_states.len(),
39        }
40    }
41
42    pub const fn is_empty(&self) -> bool {
43        matches!(self, Self::Empty)
44    }
45
46    pub fn return_state(&self, index: usize) -> Option<usize> {
47        match self {
48            Self::Empty if index == 0 => Some(EMPTY_RETURN_STATE),
49            Self::Singleton { return_state, .. } if index == 0 => Some(*return_state),
50            Self::Array { return_states, .. } => return_states.get(index).copied(),
51            Self::Empty => None,
52            Self::Singleton { .. } => None,
53        }
54    }
55
56    pub fn parent(&self, index: usize) -> Option<Rc<Self>> {
57        match self {
58            Self::Empty => None,
59            Self::Singleton { parent, .. } if index == 0 => Some(Rc::clone(parent)),
60            Self::Array { parents, .. } => parents.get(index).cloned(),
61            Self::Singleton { .. } => None,
62        }
63    }
64
65    /// Merges two prediction contexts while preserving deterministic entry
66    /// order.
67    ///
68    /// This is a compact baseline for parser ATN work: equal contexts are
69    /// reused directly, and unequal singleton/array contexts are flattened into
70    /// a deduplicated array context.
71    pub fn merge(left: Rc<Self>, right: Rc<Self>) -> Rc<Self> {
72        if left == right {
73            return left;
74        }
75        if left.is_empty() || right.is_empty() {
76            return Rc::new(Self::Array {
77                parents: vec![left, right],
78                return_states: vec![EMPTY_RETURN_STATE, EMPTY_RETURN_STATE],
79            });
80        }
81
82        let mut entries = Vec::new();
83        collect_entries(&left, &mut entries);
84        collect_entries(&right, &mut entries);
85        entries.sort_by_key(|(_, return_state)| *return_state);
86        entries.dedup_by(|a, b| a.1 == b.1 && a.0 == b.0);
87        Rc::new(Self::Array {
88            parents: entries
89                .iter()
90                .map(|(parent, _)| Rc::clone(parent))
91                .collect(),
92            return_states: entries
93                .iter()
94                .map(|(_, return_state)| *return_state)
95                .collect(),
96        })
97    }
98}
99
100fn collect_entries(
101    context: &Rc<PredictionContext>,
102    entries: &mut Vec<(Rc<PredictionContext>, usize)>,
103) {
104    match context.as_ref() {
105        PredictionContext::Empty => entries.push((Rc::clone(context), EMPTY_RETURN_STATE)),
106        PredictionContext::Singleton {
107            parent,
108            return_state,
109        } => entries.push((Rc::clone(parent), *return_state)),
110        PredictionContext::Array {
111            parents,
112            return_states,
113        } => {
114            for (parent, return_state) in parents.iter().zip(return_states) {
115                entries.push((Rc::clone(parent), *return_state));
116            }
117        }
118    }
119}
120
121#[derive(Clone, Debug, Eq, Hash, PartialEq)]
122pub struct AtnConfig {
123    pub state: usize,
124    pub alt: usize,
125    pub context: Rc<PredictionContext>,
126    pub reaches_into_outer_context: usize,
127}
128
129impl AtnConfig {
130    pub const fn new(state: usize, alt: usize, context: Rc<PredictionContext>) -> Self {
131        Self {
132            state,
133            alt,
134            context,
135            reaches_into_outer_context: 0,
136        }
137    }
138}
139
140#[derive(Clone, Debug, Default, Eq, PartialEq)]
141pub struct AtnConfigSet {
142    configs: Vec<AtnConfig>,
143    has_semantic_context: bool,
144    dips_into_outer_context: bool,
145    readonly: bool,
146}
147
148impl AtnConfigSet {
149    pub fn new() -> Self {
150        Self::default()
151    }
152
153    /// Adds a configuration if an equivalent `(state, alt, context)` entry is
154    /// not already present.
155    pub fn add(&mut self, config: AtnConfig) -> bool {
156        assert!(!self.readonly, "cannot mutate readonly ATN config set");
157        if self.configs.contains(&config) {
158            false
159        } else {
160            if config.reaches_into_outer_context > 0 {
161                self.dips_into_outer_context = true;
162            }
163            self.configs.push(config);
164            true
165        }
166    }
167
168    pub fn configs(&self) -> &[AtnConfig] {
169        &self.configs
170    }
171
172    pub const fn is_empty(&self) -> bool {
173        self.configs.is_empty()
174    }
175
176    pub const fn len(&self) -> usize {
177        self.configs.len()
178    }
179
180    pub const fn set_readonly(&mut self, readonly: bool) {
181        self.readonly = readonly;
182    }
183
184    pub const fn has_semantic_context(&self) -> bool {
185        self.has_semantic_context
186    }
187
188    pub const fn set_has_semantic_context(&mut self, value: bool) {
189        self.has_semantic_context = value;
190    }
191
192    pub const fn dips_into_outer_context(&self) -> bool {
193        self.dips_into_outer_context
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200
201    #[test]
202    fn config_set_deduplicates_configs() {
203        let empty = PredictionContext::empty();
204        let mut set = AtnConfigSet::new();
205        assert!(set.add(AtnConfig::new(1, 1, Rc::clone(&empty))));
206        assert!(!set.add(AtnConfig::new(1, 1, Rc::clone(&empty))));
207        assert_eq!(set.len(), 1);
208    }
209
210    #[test]
211    fn singleton_context_reports_parent_and_return_state() {
212        let empty = PredictionContext::empty();
213        let context = PredictionContext::singleton(Rc::clone(&empty), 42);
214        assert_eq!(context.return_state(0), Some(42));
215        assert_eq!(context.parent(0), Some(empty));
216    }
217}