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::base::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 pub fn simple(&self, _parse_cx: &ParseContext) -> (AHashSet<String>, AHashSet<String>) {
104 (self.simple.clone(), AHashSet::new())
105 }
106
107 pub fn is_first_match(&self, segment: &ErasedSegment) -> bool {
108 segment.is_code() && self.template.eq_ignore_ascii_case(segment.raw())
109 }
110}
111
112impl MatchableTrait for StringParser {
113 fn elements(&self) -> &[Matchable] {
114 &[]
115 }
116
117 fn is_optional(&self) -> bool {
118 self.optional
119 }
120
121 fn simple(
122 &self,
123 _parse_context: &ParseContext,
124 _crumbs: Option<Vec<&str>>,
125 ) -> Option<(AHashSet<String>, SyntaxSet)> {
126 (self.simple.clone(), SyntaxSet::EMPTY).into()
127 }
128
129 fn match_segments(
130 &self,
131 segments: &[ErasedSegment],
132 idx: u32,
133 _parse_context: &mut ParseContext,
134 ) -> Result<MatchResult, SQLParseError> {
135 let segment = &segments[idx as usize];
136
137 if segment.is_code() && self.template.eq_ignore_ascii_case(segment.raw()) {
138 return Ok(MatchResult {
139 span: Span {
140 start: idx,
141 end: idx + 1,
142 },
143 matched: Matched::Newtype(self.kind).into(),
144 insert_segments: Vec::new(),
145 child_matches: Vec::new(),
146 });
147 }
148
149 Ok(MatchResult::empty_at(idx))
150 }
151
152 fn cache_key(&self) -> MatchableCacheKey {
153 self.cache_key
154 }
155}
156
157#[derive(Debug, Clone)]
158pub struct RegexParser {
159 pub template: Regex,
160 pub anti_template: Option<Regex>,
161 kind: SyntaxKind,
162 cache_key: MatchableCacheKey,
163}
164
165impl PartialEq for RegexParser {
166 fn eq(&self, other: &Self) -> bool {
167 self.template.as_str() == other.template.as_str()
168 && self
169 .anti_template
170 .as_ref()
171 .zip(other.anti_template.as_ref())
172 .is_some_and(|(lhs, rhs)| lhs.as_str() == rhs.as_str())
173 && self.kind == other.kind
174 }
175}
176
177impl RegexParser {
178 pub fn new(template: &str, kind: SyntaxKind) -> Self {
179 let template_pattern = Regex::new(&format!("(?i){}", template)).unwrap();
180
181 Self {
182 template: template_pattern,
183 anti_template: None,
184 kind,
185 cache_key: next_matchable_cache_key(),
186 }
187 }
188
189 pub fn anti_template(mut self, anti_template: &str) -> Self {
190 self.anti_template = Regex::new(&format!("(?i){anti_template}")).unwrap().into();
191 self
192 }
193}
194
195impl MatchableTrait for RegexParser {
196 fn elements(&self) -> &[Matchable] {
197 &[]
198 }
199
200 fn is_optional(&self) -> bool {
201 unimplemented!()
202 }
203
204 fn simple(
205 &self,
206 _parse_context: &ParseContext,
207 _crumbs: Option<Vec<&str>>,
208 ) -> Option<(AHashSet<String>, SyntaxSet)> {
209 None
212 }
213
214 fn match_segments(
215 &self,
216 segments: &[ErasedSegment],
217 idx: u32,
218 _parse_context: &mut ParseContext,
219 ) -> Result<MatchResult, SQLParseError> {
220 let segment = &segments[idx as usize];
221 let segment_raw_upper =
222 SmolStr::from_iter(segment.raw().chars().map(|ch| ch.to_ascii_uppercase()));
223 if let Some(result) = self.template.find(&segment_raw_upper).ok().flatten() {
224 if result.as_str() == segment_raw_upper
225 && !self.anti_template.as_ref().is_some_and(|anti_template| {
226 anti_template
227 .is_match(&segment_raw_upper)
228 .unwrap_or_default()
229 })
230 {
231 return Ok(MatchResult {
232 span: Span {
233 start: idx,
234 end: idx + 1,
235 },
236 matched: Matched::Newtype(self.kind).into(),
237 insert_segments: Vec::new(),
238 child_matches: Vec::new(),
239 });
240 }
241 }
242
243 Ok(MatchResult::empty_at(idx))
244 }
245
246 fn cache_key(&self) -> MatchableCacheKey {
247 self.cache_key
248 }
249}
250
251#[derive(Clone, Debug, PartialEq)]
252pub struct MultiStringParser {
253 templates: AHashSet<String>,
254 simple: AHashSet<String>,
255 kind: SyntaxKind,
256 cache: MatchableCacheKey,
257}
258
259impl MultiStringParser {
260 pub fn new(templates: Vec<String>, kind: SyntaxKind) -> Self {
261 let templates = templates
262 .iter()
263 .map(|template| template.to_ascii_uppercase())
264 .collect::<AHashSet<String>>();
265
266 let _simple = templates.clone();
267
268 Self {
269 templates: templates.into_iter().collect(),
270 simple: _simple.into_iter().collect(),
271 kind,
272 cache: next_matchable_cache_key(),
273 }
274 }
275}
276
277impl MatchableTrait for MultiStringParser {
278 fn elements(&self) -> &[Matchable] {
279 &[]
280 }
281
282 fn is_optional(&self) -> bool {
283 todo!()
284 }
285
286 fn simple(
287 &self,
288 _parse_context: &ParseContext,
289 _crumbs: Option<Vec<&str>>,
290 ) -> Option<(AHashSet<String>, SyntaxSet)> {
291 (self.simple.clone(), SyntaxSet::EMPTY).into()
292 }
293
294 fn match_segments(
295 &self,
296 segments: &[ErasedSegment],
297 idx: u32,
298 _parse_context: &mut ParseContext,
299 ) -> Result<MatchResult, SQLParseError> {
300 let segment = &segments[idx as usize];
301
302 if segment.is_code() && self.templates.contains(&segment.raw().to_ascii_uppercase()) {
303 return Ok(MatchResult {
304 span: Span {
305 start: idx,
306 end: idx + 1,
307 },
308 matched: Matched::Newtype(self.kind).into(),
309 ..<_>::default()
310 });
311 }
312
313 Ok(MatchResult::empty_at(idx))
314 }
315
316 fn cache_key(&self) -> MatchableCacheKey {
317 self.cache
318 }
319}