sqruff_lib_core/parser/grammar/
delimited.rs

1use std::ops::{Deref, DerefMut};
2
3use ahash::AHashSet;
4
5use super::anyof::{AnyNumberOf, one_of};
6use super::base::Ref;
7use crate::dialects::syntax::SyntaxSet;
8use crate::errors::SQLParseError;
9use crate::helpers::ToMatchable;
10use crate::parser::context::ParseContext;
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::base::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    optional: bool,
30    cache_key: MatchableCacheKey,
31}
32
33impl Delimited {
34    pub fn new(elements: Vec<Matchable>) -> Self {
35        Self {
36            base: one_of(elements),
37            allow_trailing: false,
38            delimiter: Ref::new("CommaSegment").to_matchable(),
39            min_delimiters: 0,
40            optional: false,
41            cache_key: next_matchable_cache_key(),
42        }
43    }
44
45    pub fn allow_trailing(&mut self) {
46        self.allow_trailing = true;
47    }
48
49    pub fn delimiter(&mut self, delimiter: impl ToMatchable) {
50        self.delimiter = delimiter.to_matchable();
51    }
52}
53
54impl PartialEq for Delimited {
55    fn eq(&self, other: &Self) -> bool {
56        self.base == other.base && self.allow_trailing == other.allow_trailing
57        // && self.delimiter == other.delimiter
58    }
59}
60
61impl MatchableTrait for Delimited {
62    fn elements(&self) -> &[Matchable] {
63        &self.elements
64    }
65
66    fn is_optional(&self) -> bool {
67        self.optional || self.base.is_optional()
68    }
69
70    fn simple(
71        &self,
72        parse_context: &ParseContext,
73        crumbs: Option<Vec<&str>>,
74    ) -> Option<(AHashSet<String>, SyntaxSet)> {
75        super::anyof::simple(&self.elements, parse_context, crumbs)
76    }
77
78    /// Match an arbitrary number of elements separated by a delimiter.
79    ///
80    /// Note that if there are multiple elements passed in that they will be
81    /// treated as different options of what can be delimited, rather than a
82    /// sequence.
83    fn match_segments(
84        &self,
85        segments: &[ErasedSegment],
86        idx: u32,
87        parse_context: &mut ParseContext,
88    ) -> Result<MatchResult, SQLParseError> {
89        let mut delimiters = 0;
90        let mut seeking_delimiter = false;
91        let max_idx = segments.len() as u32;
92        let mut working_idx = idx;
93        let mut working_match = MatchResult::empty_at(idx);
94        let mut delimiter_match = None;
95
96        let delimiter_matcher = self.delimiter.clone();
97
98        let mut terminator_matchers = self.terminators.clone();
99        terminator_matchers.extend(
100            parse_context
101                .terminators
102                .iter()
103                .filter(|&t| &delimiter_matcher != t)
104                .cloned(),
105        );
106
107        let delimiter_matchers = &[self.delimiter.clone()];
108
109        if !self.allow_gaps {
110            terminator_matchers.push(NonCodeMatcher.to_matchable());
111        }
112
113        loop {
114            if self.allow_gaps && working_idx > idx {
115                working_idx =
116                    skip_start_index_forward_to_code(segments, working_idx, segments.len() as u32);
117            }
118
119            if working_idx >= max_idx {
120                break;
121            }
122
123            let (match_result, _) = parse_context.deeper_match(false, &[], |this| {
124                longest_match(segments, &terminator_matchers, working_idx, this)
125            })?;
126
127            if match_result.has_match() {
128                break;
129            }
130
131            let mut push_terminators: &[_] = &[];
132            if !seeking_delimiter {
133                push_terminators = delimiter_matchers;
134            }
135
136            let (match_result, _) =
137                parse_context.deeper_match(false, push_terminators, |this| {
138                    longest_match(
139                        segments,
140                        if seeking_delimiter {
141                            delimiter_matchers
142                        } else {
143                            &self.elements
144                        },
145                        working_idx,
146                        this,
147                    )
148                })?;
149
150            if !match_result.has_match() {
151                break;
152            }
153
154            working_idx = match_result.span.end;
155
156            if seeking_delimiter {
157                delimiter_match = match_result.into();
158            } else {
159                if let Some(delimiter_match) = &delimiter_match {
160                    delimiters += 1;
161                    working_match = working_match.append(delimiter_match);
162                }
163                working_match = working_match.append(match_result);
164            }
165
166            seeking_delimiter = !seeking_delimiter;
167        }
168
169        if let Some(delimiter_match) =
170            delimiter_match.filter(|_delimiter_match| self.allow_trailing && !seeking_delimiter)
171        {
172            delimiters += 1;
173            working_match = working_match.append(delimiter_match);
174        }
175
176        if delimiters < self.min_delimiters {
177            return Ok(MatchResult::empty_at(idx));
178        }
179
180        Ok(working_match)
181    }
182
183    fn cache_key(&self) -> MatchableCacheKey {
184        self.cache_key
185    }
186}
187
188impl Deref for Delimited {
189    type Target = AnyNumberOf;
190
191    fn deref(&self) -> &Self::Target {
192        &self.base
193    }
194}
195
196impl DerefMut for Delimited {
197    fn deref_mut(&mut self) -> &mut Self::Target {
198        &mut self.base
199    }
200}