sqruff_lib_core/parser/
grammar.rs

1pub 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    // Constructor function
47    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    // Static method to create a Ref instance for a keyword
81    #[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}