sqruff_lib_core/parser/
context.rs

1use ahash::AHashMap;
2use rustc_hash::FxHashMap;
3use smol_str::SmolStr;
4
5use super::match_result::MatchResult;
6use super::matchable::{Matchable, MatchableCacheKey};
7use crate::dialects::Dialect;
8use crate::dialects::syntax::SyntaxKind;
9use crate::helpers::IndexSet;
10use crate::parser::Parser;
11
12type LocKey = u32;
13type LocKeyData = (SmolStr, (usize, usize), SyntaxKind, u32);
14
15#[derive(Debug, PartialEq, Eq, Hash)]
16pub struct CacheKey {
17    loc: LocKey,
18    key: MatchableCacheKey,
19}
20
21impl CacheKey {
22    pub fn new(loc: LocKey, key: MatchableCacheKey) -> Self {
23        Self { loc, key }
24    }
25}
26
27#[derive(Debug)]
28pub struct ParseContext<'a> {
29    dialect: &'a Dialect,
30    pub(crate) terminators: Vec<Matchable>,
31    loc_keys: IndexSet<LocKeyData>,
32    parse_cache: FxHashMap<CacheKey, MatchResult>,
33    pub(crate) indentation_config: &'a AHashMap<String, bool>,
34}
35
36impl<'a> From<&'a Parser<'a>> for ParseContext<'a> {
37    fn from(parser: &'a Parser) -> Self {
38        let dialect = parser.dialect();
39        let indentation_config = &parser.indentation_config;
40        Self::new(dialect, indentation_config)
41    }
42}
43
44impl<'a> ParseContext<'a> {
45    pub fn new(dialect: &'a Dialect, indentation_config: &'a AHashMap<String, bool>) -> Self {
46        Self {
47            dialect,
48            terminators: Vec::new(),
49            loc_keys: IndexSet::default(),
50            parse_cache: FxHashMap::default(),
51            indentation_config,
52        }
53    }
54
55    pub fn dialect(&self) -> &Dialect {
56        self.dialect
57    }
58
59    pub(crate) fn deeper_match<T>(
60        &mut self,
61        clear_terminators: bool,
62        push_terminators: &[Matchable],
63        f: impl FnOnce(&mut Self) -> T,
64    ) -> T {
65        let (appended, terms) = self.set_terminators(clear_terminators, push_terminators);
66
67        let ret = f(self);
68        self.reset_terminators(appended, terms, clear_terminators);
69
70        ret
71    }
72
73    fn set_terminators(
74        &mut self,
75        clear_terminators: bool,
76        push_terminators: &[Matchable],
77    ) -> (usize, Vec<Matchable>) {
78        let mut appended = 0;
79        let terminators = self.terminators.clone();
80
81        if clear_terminators && !self.terminators.is_empty() {
82            self.terminators = if !push_terminators.is_empty() {
83                push_terminators.to_vec()
84            } else {
85                Vec::new()
86            };
87        } else if !push_terminators.is_empty() {
88            for terminator in push_terminators {
89                let terminator_owned = terminator.clone();
90
91                if !self.terminators.contains(terminator) {
92                    self.terminators.push(terminator_owned);
93                    appended += 1;
94                }
95            }
96        }
97
98        (appended, terminators)
99    }
100
101    fn reset_terminators(
102        &mut self,
103        appended: usize,
104        terminators: Vec<Matchable>,
105        clear_terminators: bool,
106    ) {
107        if clear_terminators {
108            self.terminators = terminators;
109        } else {
110            let new_len = self.terminators.len().saturating_sub(appended);
111            self.terminators.truncate(new_len);
112        }
113    }
114
115    pub(crate) fn loc_key(&mut self, data: LocKeyData) -> LocKey {
116        let (key, _) = self.loc_keys.insert_full(data);
117        key as u32
118    }
119
120    pub(crate) fn check_parse_cache(
121        &self,
122        loc_key: LocKey,
123        matcher_key: MatchableCacheKey,
124    ) -> Option<MatchResult> {
125        self.parse_cache
126            .get(&CacheKey::new(loc_key, matcher_key))
127            .cloned()
128    }
129
130    pub(crate) fn put_parse_cache(
131        &mut self,
132        loc_key: LocKey,
133        matcher_key: MatchableCacheKey,
134        match_result: MatchResult,
135    ) {
136        self.parse_cache
137            .insert(CacheKey::new(loc_key, matcher_key), match_result);
138    }
139}