1use ahash::AHashSet;
2use fancy_regex::Regex;
3use smol_str::SmolStr;
4
5use super::context::ParseContext;
6use super::match_result::{MatchResult, Matched, Span};
7use super::matchable::{Matchable, MatchableCacheKey, MatchableTrait, next_matchable_cache_key};
8use super::segments::ErasedSegment;
9use crate::dialects::syntax::{SyntaxKind, SyntaxSet};
10use crate::errors::SQLParseError;
11
12#[derive(Debug, Clone, PartialEq)]
13pub struct TypedParser {
14 template: SyntaxKind,
15 target_types: SyntaxSet,
16 kind: SyntaxKind,
17 optional: bool,
18 cache_key: MatchableCacheKey,
19}
20
21impl TypedParser {
22 pub fn new(template: SyntaxKind, kind: SyntaxKind) -> Self {
23 let target_types = SyntaxSet::new(&[template]);
24
25 Self {
26 template,
27 kind,
28 target_types,
29 optional: false,
30 cache_key: next_matchable_cache_key(),
31 }
32 }
33
34 pub fn is_first_match(&self, segment: &ErasedSegment) -> bool {
35 self.target_types.contains(segment.get_type())
36 }
37}
38
39impl MatchableTrait for TypedParser {
40 fn elements(&self) -> &[Matchable] {
41 &[]
42 }
43
44 fn simple(
45 &self,
46 parse_context: &ParseContext,
47 crumbs: Option<Vec<&str>>,
48 ) -> Option<(AHashSet<String>, SyntaxSet)> {
49 let _ = (parse_context, crumbs);
50 (AHashSet::new(), self.target_types.clone()).into()
51 }
52
53 fn match_segments(
54 &self,
55 segments: &[ErasedSegment],
56 idx: u32,
57 _parse_context: &mut ParseContext,
58 ) -> Result<MatchResult, SQLParseError> {
59 let segment = &segments[idx as usize];
60 if segment.is_type(self.template) {
61 return Ok(MatchResult {
62 span: Span {
63 start: idx,
64 end: idx + 1,
65 },
66 matched: Matched::Newtype(self.kind).into(),
67 insert_segments: Vec::new(),
68 child_matches: Vec::new(),
69 });
70 }
71
72 Ok(MatchResult::empty_at(idx))
73 }
74
75 fn cache_key(&self) -> MatchableCacheKey {
76 self.cache_key
77 }
78}
79
80#[derive(Clone, Debug, PartialEq)]
81pub struct StringParser {
82 template: String,
83 simple: AHashSet<String>,
84 kind: SyntaxKind,
85 optional: bool,
86 cache_key: MatchableCacheKey,
87}
88
89impl StringParser {
90 pub fn new(template: &str, kind: SyntaxKind) -> StringParser {
91 let template_upper = template.to_uppercase();
92 let simple_set = [template_upper.clone()].into();
93
94 StringParser {
95 template: template_upper,
96 simple: simple_set,
97 kind,
98 optional: false,
99 cache_key: next_matchable_cache_key(),
100 }
101 }
102}
103
104impl MatchableTrait for StringParser {
105 fn elements(&self) -> &[Matchable] {
106 &[]
107 }
108
109 fn is_optional(&self) -> bool {
110 self.optional
111 }
112
113 fn simple(
114 &self,
115 _parse_context: &ParseContext,
116 _crumbs: Option<Vec<&str>>,
117 ) -> Option<(AHashSet<String>, SyntaxSet)> {
118 (self.simple.clone(), SyntaxSet::EMPTY).into()
119 }
120
121 fn match_segments(
122 &self,
123 segments: &[ErasedSegment],
124 idx: u32,
125 _parse_context: &mut ParseContext,
126 ) -> Result<MatchResult, SQLParseError> {
127 let segment = &segments[idx as usize];
128
129 if segment.is_code() && self.template.eq_ignore_ascii_case(segment.raw()) {
130 return Ok(MatchResult {
131 span: Span {
132 start: idx,
133 end: idx + 1,
134 },
135 matched: Matched::Newtype(self.kind).into(),
136 insert_segments: Vec::new(),
137 child_matches: Vec::new(),
138 });
139 }
140
141 Ok(MatchResult::empty_at(idx))
142 }
143
144 fn cache_key(&self) -> MatchableCacheKey {
145 self.cache_key
146 }
147}
148
149#[derive(Debug, Clone)]
150pub struct RegexParser {
151 pub template: Regex,
152 pub anti_template: Option<Regex>,
153 kind: SyntaxKind,
154 cache_key: MatchableCacheKey,
155}
156
157impl PartialEq for RegexParser {
158 fn eq(&self, other: &Self) -> bool {
159 self.template.as_str() == other.template.as_str()
160 && self
161 .anti_template
162 .as_ref()
163 .zip(other.anti_template.as_ref())
164 .is_some_and(|(lhs, rhs)| lhs.as_str() == rhs.as_str())
165 && self.kind == other.kind
166 }
167}
168
169impl RegexParser {
170 pub fn new(template: &str, kind: SyntaxKind) -> Self {
171 let template_pattern = Regex::new(&format!("(?i){template}")).unwrap();
172
173 Self {
174 template: template_pattern,
175 anti_template: None,
176 kind,
177 cache_key: next_matchable_cache_key(),
178 }
179 }
180
181 pub fn anti_template(mut self, anti_template: &str) -> Self {
182 self.anti_template = Regex::new(&format!("(?i){anti_template}")).unwrap().into();
183 self
184 }
185}
186
187impl MatchableTrait for RegexParser {
188 fn elements(&self) -> &[Matchable] {
189 &[]
190 }
191
192 fn is_optional(&self) -> bool {
193 unimplemented!()
194 }
195
196 fn simple(
197 &self,
198 _parse_context: &ParseContext,
199 _crumbs: Option<Vec<&str>>,
200 ) -> Option<(AHashSet<String>, SyntaxSet)> {
201 None
204 }
205
206 fn match_segments(
207 &self,
208 segments: &[ErasedSegment],
209 idx: u32,
210 _parse_context: &mut ParseContext,
211 ) -> Result<MatchResult, SQLParseError> {
212 let segment = &segments[idx as usize];
213 let segment_raw_upper =
214 SmolStr::from_iter(segment.raw().chars().map(|ch| ch.to_ascii_uppercase()));
215 if let Some(result) = self.template.find(&segment_raw_upper).ok().flatten()
216 && result.as_str() == segment_raw_upper
217 && !self.anti_template.as_ref().is_some_and(|anti_template| {
218 anti_template
219 .is_match(&segment_raw_upper)
220 .unwrap_or_default()
221 })
222 {
223 return Ok(MatchResult {
224 span: Span {
225 start: idx,
226 end: idx + 1,
227 },
228 matched: Matched::Newtype(self.kind).into(),
229 insert_segments: Vec::new(),
230 child_matches: Vec::new(),
231 });
232 }
233
234 Ok(MatchResult::empty_at(idx))
235 }
236
237 fn cache_key(&self) -> MatchableCacheKey {
238 self.cache_key
239 }
240}
241
242#[derive(Clone, Debug, PartialEq)]
243pub struct MultiStringParser {
244 templates: AHashSet<String>,
245 simple: AHashSet<String>,
246 kind: SyntaxKind,
247 cache: MatchableCacheKey,
248}
249
250impl MultiStringParser {
251 pub fn new(templates: Vec<String>, kind: SyntaxKind) -> Self {
252 let templates = templates
253 .iter()
254 .map(|template| template.to_ascii_uppercase())
255 .collect::<AHashSet<String>>();
256
257 let _simple = templates.clone();
258
259 Self {
260 templates: templates.into_iter().collect(),
261 simple: _simple.into_iter().collect(),
262 kind,
263 cache: next_matchable_cache_key(),
264 }
265 }
266}
267
268impl MatchableTrait for MultiStringParser {
269 fn elements(&self) -> &[Matchable] {
270 &[]
271 }
272
273 fn is_optional(&self) -> bool {
274 todo!()
275 }
276
277 fn simple(
278 &self,
279 _parse_context: &ParseContext,
280 _crumbs: Option<Vec<&str>>,
281 ) -> Option<(AHashSet<String>, SyntaxSet)> {
282 (self.simple.clone(), SyntaxSet::EMPTY).into()
283 }
284
285 fn match_segments(
286 &self,
287 segments: &[ErasedSegment],
288 idx: u32,
289 _parse_context: &mut ParseContext,
290 ) -> Result<MatchResult, SQLParseError> {
291 let segment = &segments[idx as usize];
292
293 if segment.is_code() && self.templates.contains(&segment.raw().to_ascii_uppercase()) {
294 return Ok(MatchResult {
295 span: Span {
296 start: idx,
297 end: idx + 1,
298 },
299 matched: Matched::Newtype(self.kind).into(),
300 ..<_>::default()
301 });
302 }
303
304 Ok(MatchResult::empty_at(idx))
305 }
306
307 fn cache_key(&self) -> MatchableCacheKey {
308 self.cache
309 }
310}