sqruff_lib_core/parser/
context.rs1use 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}