sqruff_lib_core/
dialects.rs1pub mod common;
2pub mod init;
3pub mod syntax;
4
5use std::borrow::Cow;
6use std::collections::hash_map::Entry;
7use std::fmt::Debug;
8
9use ahash::{AHashMap, AHashSet};
10
11use crate::dialects::init::DialectKind;
12use crate::dialects::syntax::SyntaxKind;
13use crate::helpers::{ToMatchable, capitalize};
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: Option<Vec<Matcher>>,
23 library: AHashMap<Cow<'static, str>, DialectElementType>,
24 sets: AHashMap<&'static str, AHashSet<&'static str>>,
25 pub bracket_collections: AHashMap<&'static str, AHashSet<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(
48 &mut self,
49 iter: impl IntoIterator<Item = (Cow<'static, str>, DialectElementType)> + Clone,
50 ) {
51 self.library.extend(iter);
52 }
53
54 pub fn grammar(&self, name: &str) -> Matchable {
55 match self
56 .library
57 .get(name)
58 .unwrap_or_else(|| panic!("not found {name}"))
59 {
60 DialectElementType::Matchable(matchable) => matchable.clone(),
61 DialectElementType::SegmentGenerator(_) => {
62 unreachable!("Attempted to fetch non grammar [{name}] with `Dialect::grammar`.")
63 }
64 }
65 }
66
67 #[track_caller]
68 pub fn replace_grammar(&mut self, name: &'static str, match_grammar: Matchable) {
69 match self
70 .library
71 .get_mut(name)
72 .unwrap_or_else(|| panic!("Failed to get mutable reference for {name}"))
73 {
74 DialectElementType::Matchable(matchable) => {
75 matchable.as_node_matcher().unwrap().match_grammar = match_grammar;
76 }
77 DialectElementType::SegmentGenerator(_) => {
78 unreachable!("Attempted to fetch non grammar [{name}] with `Dialect::grammar`.")
79 }
80 }
81 }
82
83 pub fn lexer_matchers(&self) -> &[Matcher] {
84 match &self.lexer_matchers {
85 Some(lexer_matchers) => lexer_matchers,
86 None => panic!("Lexing struct has not been set for dialect {self:?}"),
87 }
88 }
89
90 pub fn insert_lexer_matchers(&mut self, lexer_patch: Vec<Matcher>, before: &str) {
91 let mut buff = Vec::new();
92 let mut found = false;
93
94 if self.lexer_matchers.is_none() {
95 panic!("Lexer struct must be defined before it can be patched!");
96 }
97
98 for elem in self.lexer_matchers.take().unwrap() {
99 if elem.name() == before {
100 found = true;
101 for patch in lexer_patch.clone() {
102 buff.push(patch);
103 }
104 buff.push(elem);
105 } else {
106 buff.push(elem);
107 }
108 }
109
110 if !found {
111 panic!("Lexer struct insert before '{before}' failed because tag never found.");
112 }
113
114 self.lexer_matchers = Some(buff);
115 }
116
117 pub fn patch_lexer_matchers(&mut self, lexer_patch: Vec<Matcher>) {
118 let mut buff = Vec::with_capacity(self.lexer_matchers.as_ref().map_or(0, Vec::len));
119 if self.lexer_matchers.is_none() {
120 panic!("Lexer struct must be defined before it can be patched!");
121 }
122
123 let patch_dict: AHashMap<&'static str, Matcher> = lexer_patch
124 .into_iter()
125 .map(|elem| (elem.name(), elem))
126 .collect();
127
128 for elem in self.lexer_matchers.take().unwrap() {
129 if let Some(patch) = patch_dict.get(elem.name()) {
130 buff.push(patch.clone());
131 } else {
132 buff.push(elem);
133 }
134 }
135
136 self.lexer_matchers = Some(buff);
137 }
138
139 pub fn set_lexer_matchers(&mut self, lexer_matchers: Vec<Matcher>) {
140 self.lexer_matchers = lexer_matchers.into();
141 }
142
143 pub fn sets(&self, label: &str) -> AHashSet<&'static str> {
144 match label {
145 "bracket_pairs" | "angle_bracket_pairs" => {
146 panic!("Use `bracket_sets` to retrieve {} set.", label);
147 }
148 _ => (),
149 }
150
151 self.sets.get(label).cloned().unwrap_or_default()
152 }
153
154 pub fn sets_mut(&mut self, label: &'static str) -> &mut AHashSet<&'static str> {
155 assert!(
156 label != "bracket_pairs" && label != "angle_bracket_pairs",
157 "Use `bracket_sets` to retrieve {} set.",
158 label
159 );
160
161 match self.sets.entry(label) {
162 Entry::Occupied(entry) => entry.into_mut(),
163 Entry::Vacant(entry) => entry.insert(<_>::default()),
164 }
165 }
166
167 pub fn update_keywords_set_from_multiline_string(
168 &mut self,
169 set_label: &'static str,
170 values: &'static str,
171 ) {
172 let keywords = values.lines().map(str::trim);
173 self.sets_mut(set_label).extend(keywords);
174 }
175
176 pub fn add_keyword_to_set(&mut self, set_label: &'static str, value: &'static str) {
177 self.sets_mut(set_label).insert(value);
178 }
179
180 pub fn bracket_sets(&self, label: &str) -> AHashSet<BracketPair> {
181 assert!(
182 label == "bracket_pairs" || label == "angle_bracket_pairs",
183 "Invalid bracket set. Consider using another identifier instead."
184 );
185
186 self.bracket_collections
187 .get(label)
188 .cloned()
189 .unwrap_or_default()
190 }
191
192 pub fn bracket_sets_mut(&mut self, label: &'static str) -> &mut AHashSet<BracketPair> {
193 assert!(
194 label == "bracket_pairs" || label == "angle_bracket_pairs",
195 "Invalid bracket set. Consider using another identifier instead."
196 );
197
198 self.bracket_collections.entry(label).or_default()
199 }
200
201 pub fn update_bracket_sets(&mut self, label: &'static str, pairs: Vec<BracketPair>) {
202 let set = self.bracket_sets_mut(label);
203 for pair in pairs {
204 set.insert(pair);
205 }
206 }
207
208 pub fn r#ref(&self, name: &str) -> Matchable {
209 match self.library.get(name) {
210 Some(DialectElementType::Matchable(matchable)) => matchable.clone(),
211 Some(DialectElementType::SegmentGenerator(_)) => {
212 panic!("Unexpected SegmentGenerator while fetching '{}'", name);
213 }
214 None => {
215 if let Some(keyword) = name.strip_suffix("KeywordSegment") {
216 let keyword_tip = "\
217 \n\nThe syntax in the query is not (yet?) supported. Try to \
218 narrow down your query to a minimal, reproducible case and \
219 raise an issue on GitHub.\n\n\
220 Or, even better, see this guide on how to help contribute \
221 keyword and/or dialect updates:\n\
222 https://github.com/quarylabs/sqruff";
223 panic!(
224 "Grammar refers to the '{keyword}' keyword which was not found in the \
225 dialect.{keyword_tip}",
226 );
227 } else {
228 panic!("Grammar refers to '{name}' which was not found in the dialect.",);
229 }
230 }
231 }
232 }
233
234 pub fn expand(&mut self) {
235 let mut library = std::mem::take(&mut self.library);
238 for element in library.values_mut() {
239 if let DialectElementType::SegmentGenerator(generator) = element {
240 *element = DialectElementType::Matchable(generator.expand(self));
241 }
242 }
243 self.library = library;
244
245 for keyword_set in ["unreserved_keywords", "reserved_keywords"] {
246 if let Some(keywords) = self.sets.get(keyword_set) {
247 for kw in keywords {
248 let n = format!("{}KeywordSegment", capitalize(kw));
249 if !self.library.contains_key(n.as_str()) {
250 let parser = StringParser::new(&kw.to_lowercase(), SyntaxKind::Keyword);
251
252 self.library.insert(
253 n.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);