sqruff_lib_core/parser/
grammar.rs1pub mod anyof;
2pub mod conditional;
3pub mod delimited;
4pub mod noncode;
5pub mod sequence;
6
7use ahash::AHashSet;
8use std::borrow::Cow;
9use std::sync::OnceLock;
10
11use crate::dialects::syntax::SyntaxSet;
12use crate::errors::SQLParseError;
13use crate::helpers::ToMatchable;
14use crate::parser::context::ParseContext;
15use crate::parser::match_algorithms::greedy_match;
16use crate::parser::match_result::MatchResult;
17use crate::parser::matchable::{
18 Matchable, MatchableCacheKey, MatchableTrait, next_matchable_cache_key,
19};
20use crate::parser::segments::ErasedSegment;
21
22#[derive(Clone)]
23pub struct Ref {
24 pub(crate) reference: Cow<'static, str>,
25 pub exclude: Option<Matchable>,
26 terminators: Vec<Matchable>,
27 reset_terminators: bool,
28 pub(crate) allow_gaps: bool,
29 pub(crate) optional: bool,
30 cache_key: MatchableCacheKey,
31 simple_cache: OnceLock<Option<(AHashSet<String>, SyntaxSet)>>,
32}
33
34impl std::fmt::Debug for Ref {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 write!(
37 f,
38 "<Ref: {}{}>",
39 self.reference,
40 if self.is_optional() { " [opt]" } else { "" }
41 )
42 }
43}
44
45impl Ref {
46 pub fn new(reference: impl Into<Cow<'static, str>>) -> Self {
48 Ref {
49 reference: reference.into(),
50 exclude: None,
51 terminators: Vec::new(),
52 reset_terminators: false,
53 allow_gaps: true,
54 optional: false,
55 cache_key: next_matchable_cache_key(),
56 simple_cache: OnceLock::new(),
57 }
58 }
59
60 pub fn exclude(mut self, exclude: impl ToMatchable) -> Self {
61 self.exclude = exclude.to_matchable().into();
62 self
63 }
64
65 pub fn terminators(mut self, terminators: Vec<Matchable>) -> Self {
66 self.terminators = terminators;
67 self
68 }
69
70 pub fn reset_terminators(mut self) -> Self {
71 self.reset_terminators = true;
72 self
73 }
74
75 pub fn optional(mut self) -> Self {
76 self.optional = true;
77 self
78 }
79
80 #[track_caller]
82 pub fn keyword(keyword: impl Into<Cow<'static, str>>) -> Self {
83 let keyword = keyword.into();
84
85 debug_assert!(
86 keyword.chars().all(|c| !c.is_lowercase()),
87 "Keyword references must be uppercase: {keyword}",
88 );
89
90 Ref::new(keyword)
91 }
92}
93
94impl PartialEq for Ref {
95 fn eq(&self, other: &Self) -> bool {
96 self.reference == other.reference
97 && self.reset_terminators == other.reset_terminators
98 && self.allow_gaps == other.allow_gaps
99 && self.optional == other.optional
100 }
101}
102
103impl Eq for Ref {}
104
105impl MatchableTrait for Ref {
106 fn elements(&self) -> &[Matchable] {
107 &[]
108 }
109
110 fn is_optional(&self) -> bool {
111 self.optional
112 }
113
114 fn simple(
115 &self,
116 parse_context: &ParseContext,
117 crumbs: Option<Vec<&str>>,
118 ) -> Option<(AHashSet<String>, SyntaxSet)> {
119 self.simple_cache
120 .get_or_init(|| {
121 if let Some(ref c) = crumbs
122 && c.contains(&&*self.reference)
123 {
124 let loop_string = c.join(" -> ");
125 panic!("Self referential grammar detected: {loop_string}");
126 }
127
128 let mut new_crumbs = crumbs.unwrap_or_default();
129 new_crumbs.push(&self.reference);
130
131 parse_context
132 .dialect()
133 .r#ref(&self.reference)
134 .simple(parse_context, Some(new_crumbs))
135 })
136 .clone()
137 }
138
139 fn match_segments(
140 &self,
141 segments: &[ErasedSegment],
142 idx: u32,
143 parse_context: &mut ParseContext,
144 ) -> Result<MatchResult, SQLParseError> {
145 let elem = parse_context.dialect().r#ref(&self.reference);
146
147 if let Some(exclude) = &self.exclude {
148 let ctx =
149 parse_context.deeper_match(self.reset_terminators, &self.terminators, |this| {
150 if exclude
151 .match_segments(segments, idx, this)
152 .inspect_err(|e| log::error!("Parser error: {e:?}"))
153 .is_ok_and(|match_result| match_result.has_match())
154 {
155 return Some(MatchResult::empty_at(idx));
156 }
157
158 None
159 });
160
161 if let Some(ctx) = ctx {
162 return Ok(ctx);
163 }
164 }
165
166 parse_context.deeper_match(self.reset_terminators, &self.terminators, |this| {
167 elem.match_segments(segments, idx, this)
168 })
169 }
170
171 fn cache_key(&self) -> MatchableCacheKey {
172 self.cache_key
173 }
174}
175
176#[derive(Clone, Debug)]
177pub struct Anything {
178 cache_key: MatchableCacheKey,
179 terminators: Vec<Matchable>,
180}
181
182impl PartialEq for Anything {
183 #[allow(unused_variables)]
184 fn eq(&self, other: &Self) -> bool {
185 unimplemented!()
186 }
187}
188
189impl Default for Anything {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195impl Anything {
196 pub fn new() -> Self {
197 Self {
198 cache_key: next_matchable_cache_key(),
199 terminators: Vec::new(),
200 }
201 }
202
203 pub fn terminators(mut self, terminators: Vec<Matchable>) -> Self {
204 self.terminators = terminators;
205 self
206 }
207}
208
209impl MatchableTrait for Anything {
210 fn elements(&self) -> &[Matchable] {
211 &[]
212 }
213
214 fn match_segments(
215 &self,
216 segments: &[ErasedSegment],
217 idx: u32,
218 parse_context: &mut ParseContext,
219 ) -> Result<MatchResult, SQLParseError> {
220 if self.terminators.is_empty() && parse_context.terminators.is_empty() {
221 return Ok(MatchResult::from_span(idx, segments.len() as u32));
222 }
223
224 let mut terminators = self.terminators.clone();
225 terminators.extend_from_slice(&parse_context.terminators);
226
227 greedy_match(segments, idx, parse_context, &terminators, false, true)
228 }
229
230 fn cache_key(&self) -> MatchableCacheKey {
231 self.cache_key
232 }
233}
234
235#[derive(Clone, Debug, PartialEq)]
236pub struct Nothing {}
237
238impl Default for Nothing {
239 fn default() -> Self {
240 Self::new()
241 }
242}
243
244impl Nothing {
245 pub fn new() -> Self {
246 Self {}
247 }
248}
249
250impl MatchableTrait for Nothing {
251 fn elements(&self) -> &[Matchable] {
252 &[]
253 }
254
255 fn match_segments(
256 &self,
257 _segments: &[ErasedSegment],
258 idx: u32,
259 _parse_context: &mut ParseContext,
260 ) -> Result<MatchResult, SQLParseError> {
261 Ok(MatchResult::empty_at(idx))
262 }
263}