sqruff_lib_core/
dialects.rs1pub 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
178 .lines()
179 .map(str::trim)
180 .filter(|keyword| !keyword.is_empty());
181 self.sets_mut(set_label).extend(keywords);
182 }
183
184 pub fn add_keyword_to_set(&mut self, set_label: &'static str, value: &'static str) {
185 self.sets_mut(set_label).insert(value);
186 }
187
188 pub fn bracket_sets(&self, label: &str) -> HashSet<BracketPair> {
189 let key = DialectSetKey::parse(label)
190 .as_bracket_set_name()
191 .unwrap_or_else(|| {
192 panic!("Invalid bracket set. Consider using another identifier instead.")
193 });
194
195 self.bracket_collections
196 .get(key)
197 .cloned()
198 .unwrap_or_default()
199 }
200
201 pub fn bracket_sets_mut(&mut self, label: &'static str) -> &mut HashSet<BracketPair> {
202 let key = DialectSetKey::parse(label)
203 .as_bracket_set_name()
204 .unwrap_or_else(|| {
205 panic!("Invalid bracket set. Consider using another identifier instead.")
206 });
207
208 self.bracket_collections.entry(key).or_default()
209 }
210
211 pub fn update_bracket_sets(&mut self, label: &'static str, pairs: Vec<BracketPair>) {
212 let set = self.bracket_sets_mut(label);
213 for pair in pairs {
214 set.insert(pair);
215 }
216 }
217
218 #[track_caller]
219 pub fn r#ref(&self, name: &str) -> Matchable {
220 match self.library.get(name) {
221 Some(DialectElementType::Matchable(matchable)) => matchable.clone(),
222 Some(DialectElementType::SegmentGenerator(_)) => {
223 panic!("Unexpected SegmentGenerator while fetching '{name}'");
224 }
225 None => {
226 panic!("Grammar refers to '{name}' which was not found in the dialect.",);
227 }
228 }
229 }
230
231 pub fn expand(&mut self) {
232 let mut library = std::mem::take(&mut self.library);
235 for element in library.values_mut() {
236 if let DialectElementType::SegmentGenerator(generator) = element {
237 *element = DialectElementType::Matchable(generator.expand(self));
238 }
239 }
240 self.library = library;
241
242 for keyword_set in [
243 "unreserved_keywords",
244 "reserved_keywords",
245 "future_reserved_keywords",
246 ] {
247 if let Some(keywords) = self.sets.get(keyword_set) {
248 for &kw in keywords {
249 if !self.library.contains_key(kw) {
250 let parser = StringParser::new(kw, SyntaxKind::Keyword);
251
252 self.library.insert(
253 kw.into(),
254 DialectElementType::Matchable(parser.to_matchable()),
255 );
256 }
257 }
258 }
259 }
260
261 self.lexer = Lexer::new(self.lexer_matchers()).into();
262 }
263
264 pub fn lexer(&self) -> &Lexer {
265 self.lexer.as_ref().unwrap()
266 }
267}
268
269pub type BracketPair = (&'static str, &'static str, &'static str, bool);