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::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    // Constructor function
48    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    // Method to get the referenced element
72    fn _get_elem(&self, dialect: &Dialect) -> Matchable {
73        dialect.r#ref(&self.reference)
74    }
75
76    // Static method to create a Ref instance for a keyword
77    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}