Skip to main content

sqruff_lib_core/
dialects.rs

1pub mod common;
2pub mod init;
3pub mod sets;
4pub mod syntax;
5
6use std::borrow::Cow;
7use std::fmt::Debug;
8
9use hashbrown::hash_map::Entry;
10use hashbrown::{HashMap, HashSet};
11
12use crate::dialects::init::DialectKind;
13use crate::dialects::sets::DialectSetKey;
14use crate::dialects::syntax::SyntaxKind;
15use crate::helpers::ToMatchable;
16use crate::parser::lexer::{Lexer, Matcher};
17use crate::parser::matchable::Matchable;
18use crate::parser::parsers::StringParser;
19use crate::parser::types::DialectElementType;
20
21#[derive(Debug, Clone, Default)]
22pub struct Dialect {
23    pub name: DialectKind,
24    lexer_matchers: Vec<Matcher>,
25    library: HashMap<Cow<'static, str>, DialectElementType>,
26    sets: HashMap<&'static str, HashSet<&'static str>>,
27    pub bracket_collections: HashMap<&'static str, HashSet<BracketPair>>,
28    lexer: Option<Lexer>,
29}
30
31impl PartialEq for Dialect {
32    fn eq(&self, other: &Self) -> bool {
33        self.name == other.name
34    }
35}
36
37impl Dialect {
38    pub fn new() -> Self {
39        Dialect {
40            name: DialectKind::Ansi,
41            ..Default::default()
42        }
43    }
44
45    pub fn name(&self) -> DialectKind {
46        self.name
47    }
48
49    pub fn add(&mut self, iter: impl IntoIterator<Item = (Cow<'static, str>, DialectElementType)>) {
50        self.library.extend(iter);
51    }
52
53    pub fn grammar(&self, name: &str) -> Matchable {
54        match self
55            .library
56            .get(name)
57            .unwrap_or_else(|| panic!("not found {name}"))
58        {
59            DialectElementType::Matchable(matchable) => matchable.clone(),
60            DialectElementType::SegmentGenerator(_) => {
61                unreachable!("Attempted to fetch non grammar [{name}] with `Dialect::grammar`.")
62            }
63        }
64    }
65
66    #[track_caller]
67    pub fn replace_grammar(&mut self, name: &'static str, match_grammar: Matchable) {
68        match self.library.entry(Cow::Borrowed(name)) {
69            Entry::Occupied(entry) => {
70                let target = entry.into_mut();
71                match target {
72                    DialectElementType::Matchable(matchable) => {
73                        if let Some(node_matcher) = matchable.as_node_matcher() {
74                            node_matcher.replace(match_grammar);
75                        } else {
76                            *target = DialectElementType::Matchable(match_grammar);
77                        }
78                    }
79                    DialectElementType::SegmentGenerator(_) => {
80                        *target = DialectElementType::Matchable(match_grammar);
81                    }
82                }
83            }
84            Entry::Vacant(entry) => {
85                entry.insert(match_grammar.into());
86            }
87        }
88    }
89
90    pub fn lexer_matchers(&self) -> &[Matcher] {
91        &self.lexer_matchers
92    }
93
94    pub fn insert_lexer_matchers(&mut self, lexer_patch: Vec<Matcher>, before: &str) {
95        assert!(
96            !self.lexer_matchers.is_empty(),
97            "Lexer struct must be defined before it can be patched!"
98        );
99
100        let mut buff = Vec::new();
101        let mut found = false;
102
103        for elem in std::mem::take(&mut self.lexer_matchers) {
104            if elem.name() == before {
105                found = true;
106                for patch in lexer_patch.clone() {
107                    buff.push(patch);
108                }
109                buff.push(elem);
110            } else {
111                buff.push(elem);
112            }
113        }
114
115        assert!(
116            found,
117            "Lexer struct insert before '{before}' failed because tag never found."
118        );
119
120        self.lexer_matchers = buff;
121    }
122
123    pub fn patch_lexer_matchers(&mut self, lexer_patch: Vec<Matcher>) {
124        assert!(
125            !self.lexer_matchers.is_empty(),
126            "Lexer struct must be defined before it can be patched!"
127        );
128
129        let mut buff = Vec::with_capacity(self.lexer_matchers.len());
130
131        let patch_dict: HashMap<&'static str, Matcher> = lexer_patch
132            .into_iter()
133            .map(|elem| (elem.name(), elem))
134            .collect();
135
136        for elem in std::mem::take(&mut self.lexer_matchers) {
137            if let Some(patch) = patch_dict.get(elem.name()) {
138                buff.push(patch.clone());
139            } else {
140                buff.push(elem);
141            }
142        }
143
144        self.lexer_matchers = buff;
145    }
146
147    pub fn set_lexer_matchers(&mut self, lexer_matchers: Vec<Matcher>) {
148        self.lexer_matchers = lexer_matchers;
149    }
150
151    pub fn sets(&self, label: &str) -> HashSet<&'static str> {
152        match DialectSetKey::parse(label) {
153            DialectSetKey::Named(label) => self.sets.get(label).cloned().unwrap_or_default(),
154            DialectSetKey::BracketPairs | DialectSetKey::AngleBracketPairs => {
155                panic!("Use `bracket_sets` to retrieve {label} set.");
156            }
157        }
158    }
159
160    pub fn sets_mut(&mut self, label: &'static str) -> &mut HashSet<&'static str> {
161        match DialectSetKey::parse(label) {
162            DialectSetKey::Named(label) => match self.sets.entry(label) {
163                Entry::Occupied(entry) => entry.into_mut(),
164                Entry::Vacant(entry) => entry.insert(<_>::default()),
165            },
166            DialectSetKey::BracketPairs | DialectSetKey::AngleBracketPairs => {
167                panic!("Use `bracket_sets` to retrieve {label} set.");
168            }
169        }
170    }
171
172    pub fn update_keywords_set_from_multiline_string(
173        &mut self,
174        set_label: &'static str,
175        values: &'static str,
176    ) {
177        let keywords = values.lines().map(str::trim);
178        self.sets_mut(set_label).extend(keywords);
179    }
180
181    pub fn add_keyword_to_set(&mut self, set_label: &'static str, value: &'static str) {
182        self.sets_mut(set_label).insert(value);
183    }
184
185    pub fn bracket_sets(&self, label: &str) -> HashSet<BracketPair> {
186        let key = DialectSetKey::parse(label)
187            .as_bracket_set_name()
188            .unwrap_or_else(|| {
189                panic!("Invalid bracket set. Consider using another identifier instead.")
190            });
191
192        self.bracket_collections
193            .get(key)
194            .cloned()
195            .unwrap_or_default()
196    }
197
198    pub fn bracket_sets_mut(&mut self, label: &'static str) -> &mut HashSet<BracketPair> {
199        let key = DialectSetKey::parse(label)
200            .as_bracket_set_name()
201            .unwrap_or_else(|| {
202                panic!("Invalid bracket set. Consider using another identifier instead.")
203            });
204
205        self.bracket_collections.entry(key).or_default()
206    }
207
208    pub fn update_bracket_sets(&mut self, label: &'static str, pairs: Vec<BracketPair>) {
209        let set = self.bracket_sets_mut(label);
210        for pair in pairs {
211            set.insert(pair);
212        }
213    }
214
215    #[track_caller]
216    pub fn r#ref(&self, name: &str) -> Matchable {
217        match self.library.get(name) {
218            Some(DialectElementType::Matchable(matchable)) => matchable.clone(),
219            Some(DialectElementType::SegmentGenerator(_)) => {
220                panic!("Unexpected SegmentGenerator while fetching '{name}'");
221            }
222            None => {
223                panic!("Grammar refers to '{name}' which was not found in the dialect.",);
224            }
225        }
226    }
227
228    pub fn expand(&mut self) {
229        // Temporarily take ownership of 'library' from 'self' to avoid borrow checker
230        // errors during mutation.
231        let mut library = std::mem::take(&mut self.library);
232        for element in library.values_mut() {
233            if let DialectElementType::SegmentGenerator(generator) = element {
234                *element = DialectElementType::Matchable(generator.expand(self));
235            }
236        }
237        self.library = library;
238
239        for keyword_set in [
240            "unreserved_keywords",
241            "reserved_keywords",
242            "future_reserved_keywords",
243        ] {
244            if let Some(keywords) = self.sets.get(keyword_set) {
245                for &kw in keywords {
246                    if !self.library.contains_key(kw) {
247                        let parser = StringParser::new(kw, SyntaxKind::Keyword);
248
249                        self.library.insert(
250                            kw.into(),
251                            DialectElementType::Matchable(parser.to_matchable()),
252                        );
253                    }
254                }
255            }
256        }
257
258        self.lexer = Lexer::new(self.lexer_matchers()).into();
259    }
260
261    pub fn lexer(&self) -> &Lexer {
262        self.lexer.as_ref().unwrap()
263    }
264}
265
266pub type BracketPair = (&'static str, &'static str, &'static str, bool);