Skip to main content

sqruff_lib_core/
dialects.rs

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