sqruff_lib_core/parser/grammar/
delimited.rs

1use std::ops::{Deref, DerefMut};
2
3use ahash::AHashSet;
4
5use super::anyof::{AnyNumberOf, one_of};
6use crate::dialects::syntax::SyntaxSet;
7use crate::errors::SQLParseError;
8use crate::helpers::ToMatchable;
9use crate::parser::context::ParseContext;
10use crate::parser::grammar::Ref;
11use crate::parser::grammar::noncode::NonCodeMatcher;
12use crate::parser::match_algorithms::{longest_match, skip_start_index_forward_to_code};
13use crate::parser::match_result::MatchResult;
14use crate::parser::matchable::{
15    Matchable, MatchableCacheKey, MatchableTrait, next_matchable_cache_key,
16};
17use crate::parser::segments::ErasedSegment;
18
19/// Match an arbitrary number of elements separated by a delimiter.
20///
21/// Note that if there are multiple elements passed in that they will be treated
22/// as different options of what can be delimited, rather than a sequence.
23#[derive(Clone, Debug)]
24pub struct Delimited {
25    pub base: AnyNumberOf,
26    pub allow_trailing: bool,
27    pub(crate) delimiter: Matchable,
28    pub min_delimiters: usize,
29    pub optional_delimiter: bool,
30    optional: bool,
31    cache_key: MatchableCacheKey,
32}
33
34impl Delimited {
35    pub fn new(elements: Vec<Matchable>) -> Self {
36        Self {
37            base: one_of(elements),
38            allow_trailing: false,
39            delimiter: Ref::new("CommaSegment").to_matchable(),
40            min_delimiters: 0,
41            optional_delimiter: false,
42            optional: false,
43            cache_key: next_matchable_cache_key(),
44        }
45    }
46
47    pub fn allow_trailing(&mut self) {
48        self.allow_trailing = true;
49    }
50
51    pub fn optional_delimiter(&mut self) {
52        self.optional_delimiter = true;
53    }
54
55    pub fn delimiter(&mut self, delimiter: impl ToMatchable) {
56        self.delimiter = delimiter.to_matchable();
57    }
58}
59
60impl PartialEq for Delimited {
61    fn eq(&self, other: &Self) -> bool {
62        self.base == other.base
63            && self.allow_trailing == other.allow_trailing
64            && self.optional_delimiter == other.optional_delimiter
65        // && self.delimiter == other.delimiter
66    }
67}
68
69impl MatchableTrait for Delimited {
70    fn elements(&self) -> &[Matchable] {
71        &self.elements
72    }
73
74    fn is_optional(&self) -> bool {
75        self.optional || self.base.is_optional()
76    }
77
78    fn simple(
79        &self,
80        parse_context: &ParseContext,
81        crumbs: Option<Vec<&str>>,
82    ) -> Option<(AHashSet<String>, SyntaxSet)> {
83        super::anyof::simple(&self.elements, parse_context, crumbs)
84    }
85
86    /// Match an arbitrary number of elements separated by a delimiter.
87    ///
88    /// Note that if there are multiple elements passed in that they will be
89    /// treated as different options of what can be delimited, rather than a
90    /// sequence.
91    fn match_segments(
92        &self,
93        segments: &[ErasedSegment],
94        idx: u32,
95        parse_context: &mut ParseContext,
96    ) -> Result<MatchResult, SQLParseError> {
97        let mut delimiters = 0;
98        let mut seeking_delimiter = false;
99        let max_idx = segments.len() as u32;
100        let mut working_idx = idx;
101        let mut working_match = MatchResult::empty_at(idx);
102        let mut delimiter_match = None;
103
104        let delimiter_matcher = self.delimiter.clone();
105
106        let mut terminator_matchers = self.terminators.clone();
107        terminator_matchers.extend(
108            parse_context
109                .terminators
110                .iter()
111                .filter(|&t| &delimiter_matcher != t)
112                .cloned(),
113        );
114
115        let delimiter_matchers = std::slice::from_ref(&self.delimiter);
116
117        if !self.allow_gaps {
118            terminator_matchers.push(NonCodeMatcher.to_matchable());
119        }
120
121        loop {
122            if self.allow_gaps && working_idx > idx {
123                working_idx =
124                    skip_start_index_forward_to_code(segments, working_idx, segments.len() as u32);
125            }
126
127            if working_idx >= max_idx {
128                break;
129            }
130
131            let (match_result, _) = parse_context.deeper_match(false, &[], |this| {
132                longest_match(segments, &terminator_matchers, working_idx, this)
133            })?;
134
135            if match_result.has_match() {
136                break;
137            }
138
139            let mut push_terminators: &[_] = &[];
140            if !seeking_delimiter {
141                push_terminators = delimiter_matchers;
142            }
143
144            let (match_result, _) =
145                parse_context.deeper_match(false, push_terminators, |this| {
146                    longest_match(
147                        segments,
148                        if seeking_delimiter {
149                            delimiter_matchers
150                        } else {
151                            &self.elements
152                        },
153                        working_idx,
154                        this,
155                    )
156                })?;
157
158            if !match_result.has_match() {
159                if seeking_delimiter && self.optional_delimiter {
160                    seeking_delimiter = false;
161                    continue;
162                }
163                break;
164            }
165
166            working_idx = match_result.span.end;
167
168            if seeking_delimiter {
169                delimiter_match = match_result.into();
170            } else {
171                if let Some(delimiter_match) = &delimiter_match {
172                    delimiters += 1;
173                    working_match = working_match.append(delimiter_match);
174                }
175                working_match = working_match.append(match_result);
176            }
177
178            seeking_delimiter = !seeking_delimiter;
179        }
180
181        if let Some(delimiter_match) =
182            delimiter_match.filter(|_delimiter_match| self.allow_trailing && !seeking_delimiter)
183        {
184            delimiters += 1;
185            working_match = working_match.append(delimiter_match);
186        }
187
188        if delimiters < self.min_delimiters {
189            return Ok(MatchResult::empty_at(idx));
190        }
191
192        Ok(working_match)
193    }
194
195    fn cache_key(&self) -> MatchableCacheKey {
196        self.cache_key
197    }
198
199    #[track_caller]
200    fn copy(
201        &self,
202        insert: Option<Vec<Matchable>>,
203        at: Option<usize>,
204        before: Option<Matchable>,
205        remove: Option<Vec<Matchable>>,
206        terminators: Vec<Matchable>,
207        replace_terminators: bool,
208    ) -> Matchable {
209        let mut new_elements = self.elements.clone();
210
211        if let Some(insert_elements) = insert {
212            if let Some(before_element) = before {
213                if let Some(index) = self.elements.iter().position(|e| e == &before_element) {
214                    new_elements.splice(index..index, insert_elements);
215                } else {
216                    panic!("Element for insertion before not found");
217                }
218            } else if let Some(at_index) = at {
219                new_elements.splice(at_index..at_index, insert_elements);
220            } else {
221                new_elements.extend(insert_elements);
222            }
223        }
224
225        if let Some(remove_elements) = remove {
226            new_elements.retain(|elem| !remove_elements.contains(elem));
227        }
228
229        let mut new_grammar = self.clone();
230
231        new_grammar.base.elements = new_elements;
232        new_grammar.base.terminators = if replace_terminators {
233            terminators
234        } else {
235            [self.terminators.clone(), terminators].concat()
236        };
237
238        new_grammar.to_matchable()
239    }
240}
241
242impl Deref for Delimited {
243    type Target = AnyNumberOf;
244
245    fn deref(&self) -> &Self::Target {
246        &self.base
247    }
248}
249
250impl DerefMut for Delimited {
251    fn deref_mut(&mut self) -> &mut Self::Target {
252        &mut self.base
253    }
254}