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