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