sqruff_lib_core/parser/
lookahead.rs1use ahash::AHashSet;
2
3use super::context::ParseContext;
4use super::match_algorithms::skip_start_index_forward_to_code;
5use super::match_result::MatchResult;
6use super::matchable::{Matchable, MatchableCacheKey, MatchableTrait, next_matchable_cache_key};
7use super::segments::ErasedSegment;
8use crate::dialects::syntax::SyntaxSet;
9use crate::errors::SQLParseError;
10
11#[derive(Debug, Clone, PartialEq)]
16pub struct LookaheadExclude {
17 first_token: &'static str,
19 lookahead_token: &'static str,
21 cache_key: MatchableCacheKey,
23}
24
25impl LookaheadExclude {
26 pub fn new(first_token: &'static str, lookahead_token: &'static str) -> Self {
28 Self {
29 first_token,
30 lookahead_token,
31 cache_key: next_matchable_cache_key(),
32 }
33 }
34}
35
36impl MatchableTrait for LookaheadExclude {
37 fn elements(&self) -> &[Matchable] {
38 &[]
39 }
40
41 fn is_optional(&self) -> bool {
42 false
44 }
45
46 fn simple(
47 &self,
48 _parse_context: &ParseContext,
49 _crumbs: Option<Vec<&str>>,
50 ) -> Option<(AHashSet<String>, SyntaxSet)> {
51 None
53 }
54
55 fn match_segments(
56 &self,
57 segments: &[ErasedSegment],
58 idx: u32,
59 _parse_context: &mut ParseContext,
60 ) -> Result<MatchResult, SQLParseError> {
61 if idx >= segments.len() as u32 {
63 return Ok(MatchResult::empty_at(idx));
64 }
65
66 let current_raw = segments[idx as usize].raw();
68 if current_raw.eq_ignore_ascii_case(self.first_token) {
69 let next_idx =
71 skip_start_index_forward_to_code(segments, idx + 1, segments.len() as u32);
72
73 if next_idx < segments.len() as u32 {
74 let next_raw = segments[next_idx as usize].raw();
75 if next_raw.eq_ignore_ascii_case(self.lookahead_token) {
76 return Ok(MatchResult::from_span(idx, idx + 1));
78 }
79 }
80 }
81
82 Ok(MatchResult::empty_at(idx))
84 }
85
86 fn cache_key(&self) -> MatchableCacheKey {
87 self.cache_key
88 }
89}