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 optional(mut self) -> Self {
66 self.optional = true;
67 self
68 }
69
70 #[track_caller]
72 pub fn keyword(keyword: impl Into<Cow<'static, str>>) -> Self {
73 let keyword = keyword.into();
74
75 debug_assert!(
76 keyword.chars().all(|c| !c.is_lowercase()),
77 "Keyword references must be uppercase: {keyword}",
78 );
79
80 Ref::new(keyword)
81 }
82}
83
84impl PartialEq for Ref {
85 fn eq(&self, other: &Self) -> bool {
86 self.reference == other.reference
87 && self.reset_terminators == other.reset_terminators
88 && self.allow_gaps == other.allow_gaps
89 && self.optional == other.optional
90 }
91}
92
93impl Eq for Ref {}
94
95impl MatchableTrait for Ref {
96 fn elements(&self) -> &[Matchable] {
97 &[]
98 }
99
100 fn is_optional(&self) -> bool {
101 self.optional
102 }
103
104 fn simple(
105 &self,
106 parse_context: &ParseContext,
107 crumbs: Option<Vec<&str>>,
108 ) -> Option<(AHashSet<String>, SyntaxSet)> {
109 self.simple_cache
110 .get_or_init(|| {
111 if let Some(ref c) = crumbs
112 && c.contains(&&*self.reference)
113 {
114 let loop_string = c.join(" -> ");
115 panic!("Self referential grammar detected: {loop_string}");
116 }
117
118 let mut new_crumbs = crumbs.unwrap_or_default();
119 new_crumbs.push(&self.reference);
120
121 parse_context
122 .dialect()
123 .r#ref(&self.reference)
124 .simple(parse_context, Some(new_crumbs))
125 })
126 .clone()
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 elem = parse_context.dialect().r#ref(&self.reference);
136
137 if let Some(exclude) = &self.exclude {
138 let ctx =
139 parse_context.deeper_match(self.reset_terminators, &self.terminators, |this| {
140 if exclude
141 .match_segments(segments, idx, this)
142 .inspect_err(|e| log::error!("Parser error: {e:?}"))
143 .is_ok_and(|match_result| match_result.has_match())
144 {
145 return Some(MatchResult::empty_at(idx));
146 }
147
148 None
149 });
150
151 if let Some(ctx) = ctx {
152 return Ok(ctx);
153 }
154 }
155
156 parse_context.deeper_match(self.reset_terminators, &self.terminators, |this| {
157 elem.match_segments(segments, idx, this)
158 })
159 }
160
161 fn cache_key(&self) -> MatchableCacheKey {
162 self.cache_key
163 }
164}
165
166#[derive(Clone, Debug)]
167pub struct Anything {
168 cache_key: MatchableCacheKey,
169 terminators: Vec<Matchable>,
170}
171
172impl PartialEq for Anything {
173 #[allow(unused_variables)]
174 fn eq(&self, other: &Self) -> bool {
175 unimplemented!()
176 }
177}
178
179impl Default for Anything {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185impl Anything {
186 pub fn new() -> Self {
187 Self {
188 cache_key: next_matchable_cache_key(),
189 terminators: Vec::new(),
190 }
191 }
192
193 pub fn terminators(mut self, terminators: Vec<Matchable>) -> Self {
194 self.terminators = terminators;
195 self
196 }
197}
198
199impl MatchableTrait for Anything {
200 fn elements(&self) -> &[Matchable] {
201 &[]
202 }
203
204 fn match_segments(
205 &self,
206 segments: &[ErasedSegment],
207 idx: u32,
208 parse_context: &mut ParseContext,
209 ) -> Result<MatchResult, SQLParseError> {
210 if self.terminators.is_empty() && parse_context.terminators.is_empty() {
211 return Ok(MatchResult::from_span(idx, segments.len() as u32));
212 }
213
214 let mut terminators = self.terminators.clone();
215 terminators.extend_from_slice(&parse_context.terminators);
216
217 greedy_match(segments, idx, parse_context, &terminators, false, true)
218 }
219
220 fn cache_key(&self) -> MatchableCacheKey {
221 self.cache_key
222 }
223}
224
225#[derive(Clone, Debug, PartialEq)]
226pub struct Nothing {}
227
228impl Default for Nothing {
229 fn default() -> Self {
230 Self::new()
231 }
232}
233
234impl Nothing {
235 pub fn new() -> Self {
236 Self {}
237 }
238}
239
240impl MatchableTrait for Nothing {
241 fn elements(&self) -> &[Matchable] {
242 &[]
243 }
244
245 fn match_segments(
246 &self,
247 _segments: &[ErasedSegment],
248 idx: u32,
249 _parse_context: &mut ParseContext,
250 ) -> Result<MatchResult, SQLParseError> {
251 Ok(MatchResult::empty_at(idx))
252 }
253}