Skip to main content

dbt_antlr4/
prediction_mode.rs

1use std::collections::HashMap;
2
3use bit_set::BitSet;
4
5use crate::atn::INVALID_ALT;
6use crate::atn_config::ATNConfig;
7use crate::atn_config_set::ATNConfigSet;
8use crate::atn_state::ATNStateRef;
9use crate::prediction_context::{NoopHasherBuilder, PredictionContext};
10use crate::semantic_context::SemanticContext;
11
12/// This enum defines the prediction modes available in ANTLR 4 along with
13/// utility methods for analyzing configuration sets for conflicts and/or
14/// ambiguities.
15///
16/// It is set through `ParserATNSimulator::
17#[allow(non_camel_case_types)]
18#[derive(Eq, PartialEq, Copy, Clone, Debug)]
19pub enum PredictionMode {
20    /// The SLL(*) prediction mode. This prediction mode ignores the current
21    /// parser context when making predictions. This is the fastest prediction
22    /// mode, and provides correct results for many grammars. This prediction
23    /// mode is more powerful than the prediction mode provided by ANTLR 3, but
24    /// may result in syntax errors for grammar and input combinations which are
25    /// not SLL.
26    ///
27    /// <p>
28    /// When using this prediction mode, the parser will either return a correct
29    /// parse tree (i.e. the same parse tree that would be returned with the
30    /// {@link #LL} prediction mode), or it will report a syntax error. If a
31    /// syntax error is encountered when using the {@link #SLL} prediction mode,
32    /// it may be due to either an actual syntax error in the input or indicate
33    /// that the particular combination of grammar and input requires the more
34    /// powerful {@link #LL} prediction abilities to complete successfully.</p>
35    ///
36    /// <p>
37    /// This prediction mode does not provide any guarantees for prediction
38    /// behavior for syntactically-incorrect inputs.</p>
39    ///
40    SLL = 0,
41    ///
42    /// The LL(*) prediction mode. This prediction mode allows the current parser
43    /// context to be used for resolving SLL conflicts that occur during
44    /// prediction. This is the fastest prediction mode that guarantees correct
45    /// parse results for all combinations of grammars with syntactically correct
46    /// inputs.
47    ///
48    /// <p>
49    /// When using this prediction mode, the parser will make correct decisions
50    /// for all syntactically-correct grammar and input combinations. However, in
51    /// cases where the grammar is truly ambiguous this prediction mode might not
52    /// report a precise answer for <em>exactly which</em> alternatives are
53    /// ambiguous.</p>
54    ///
55    /// <p>
56    /// This prediction mode does not provide any guarantees for prediction
57    /// behavior for syntactically-incorrect inputs.</p>
58    ///
59    LL,
60    ///
61    /// The LL(*) prediction mode with exact ambiguity detection. In addition to
62    /// the correctness guarantees provided by the {@link #LL} prediction mode,
63    /// this prediction mode instructs the prediction algorithm to determine the
64    /// complete and exact set of ambiguous alternatives for every ambiguous
65    /// decision encountered while parsing.
66    ///
67    /// <p>
68    /// This prediction mode may be used for diagnosing ambiguities during
69    /// grammar development. Due to the performance overhead of calculating sets
70    /// of ambiguous alternatives, this prediction mode should be avoided when
71    /// the exact results are not necessary.</p>
72    ///
73    /// <p>
74    /// This prediction mode does not provide any guarantees for prediction
75    /// behavior for syntactically-incorrect inputs.</p>
76    ///
77    LL_EXACT_AMBIG_DETECTION,
78}
79
80impl PredictionMode {
81    //todo move everything here
82}
83
84//
85//
86pub(crate) fn has_sll_conflict_terminating_prediction<'ephemeral>(
87    ephemerals: &'ephemeral bumpalo::Bump,
88    mode: PredictionMode,
89    configs: &ATNConfigSet<'ephemeral>,
90) -> bool {
91    //    if all_configs_in_rule_stop_states(configs) {
92    //        return true          checked outside
93    //    }
94    let mut dup = ATNConfigSet::new(ephemerals, true);
95    let mut configs = configs;
96    if mode == PredictionMode::SLL && configs.has_semantic_context() {
97        configs.get_items().for_each(|it| {
98            let c = ATNConfig::new(it.get_state(), it.get_alt(), it.get_context())
99                .with_semantic_context(&SemanticContext::NONE);
100            dup.add(c);
101        });
102        configs = &dup;
103    }
104
105    let altsets = get_conflicting_alt_subsets(configs);
106
107    has_conflicting_alt_set(&altsets) && !has_state_associated_with_one_alt(configs)
108}
109
110//fn all_configs_in_rule_stop_states(configs: &ATNConfigSet) -> bool {
111//    for co
112//}
113
114pub(crate) fn resolves_to_just_one_viable_alt(altsets: &[BitSet]) -> i32 {
115    get_single_viable_alt(altsets)
116}
117
118pub(crate) fn all_subsets_conflict(altsets: &[BitSet]) -> bool {
119    !has_non_conflicting_alt_set(altsets)
120}
121
122pub(crate) fn all_subsets_equal(altsets: &[BitSet]) -> bool {
123    let mut iter = altsets.iter();
124    let first = iter.next();
125    iter.all(|it| it == first.unwrap())
126}
127
128fn has_non_conflicting_alt_set(altsets: &[BitSet]) -> bool {
129    altsets.iter().any(|it| it.len() == 1)
130}
131
132fn has_conflicting_alt_set(altsets: &[BitSet]) -> bool {
133    for alts in altsets {
134        if alts.len() > 1 {
135            return true;
136        }
137    }
138    false
139}
140
141//fn get_unique_alt(altsets: &[BitSet]) -> int { unimplemented!() }
142//
143pub(crate) fn get_alts(altsets: &[BitSet]) -> BitSet {
144    altsets.iter().fold(BitSet::new(), |mut acc, it| {
145        acc.extend(it);
146        acc
147    })
148}
149
150pub(crate) fn get_conflicting_alt_subsets(configs: &ATNConfigSet) -> Vec<BitSet> {
151    #[derive(Eq, PartialEq)]
152    struct KeyWrapper<'a> {
153        state: ATNStateRef,
154        context: &'a PredictionContext<'a>,
155    }
156
157    impl<'a> std::hash::Hash for KeyWrapper<'a> {
158        fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159            let ptr = self.state.as_usize() as u64;
160            state.write_u64(ptr ^ (self.context.hash_code() as u64));
161        }
162    }
163
164    let mut configs_to_alts: HashMap<KeyWrapper, BitSet, _> =
165        HashMap::with_hasher(NoopHasherBuilder {});
166    for c in configs.get_items() {
167        let alts = configs_to_alts
168            .entry(KeyWrapper {
169                state: c.get_state(),
170                context: c.get_context().unwrap(),
171            })
172            .or_default();
173
174        alts.insert(c.get_alt() as usize);
175    }
176    configs_to_alts.drain().map(|(_, x)| x).collect()
177}
178
179fn get_state_to_alt_map(configs: &ATNConfigSet) -> HashMap<ATNStateRef, BitSet> {
180    let mut m = HashMap::new();
181    for c in configs.get_items() {
182        let alts = m.entry(c.get_state()).or_insert(BitSet::new());
183        alts.insert(c.get_alt() as usize);
184    }
185    m
186}
187
188fn has_state_associated_with_one_alt(configs: &ATNConfigSet) -> bool {
189    let x = get_state_to_alt_map(configs);
190    for alts in x.values() {
191        if alts.len() == 1 {
192            return true;
193        }
194    }
195    false
196}
197
198pub(crate) fn get_single_viable_alt(altsets: &[BitSet]) -> i32 {
199    let mut viable_alts = BitSet::new();
200    let mut min_alt = INVALID_ALT as usize;
201    for alt in altsets {
202        min_alt = alt.iter().next().unwrap();
203        viable_alts.insert(min_alt);
204        if viable_alts.len() > 1 {
205            return INVALID_ALT;
206        }
207    }
208    min_alt as i32
209}