sqruff_lib_core/parser/segments/
file.rs

1use crate::dialects::init::DialectKind;
2use crate::dialects::syntax::SyntaxKind;
3use crate::errors::SQLParseError;
4use crate::parser::context::ParseContext;
5use crate::parser::matchable::MatchableTrait;
6use crate::parser::segments::{ErasedSegment, SegmentBuilder, Tables};
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct FileSegment;
10
11impl FileSegment {
12    pub fn of(
13        tables: &Tables,
14        dialect: DialectKind,
15        segments: Vec<ErasedSegment>,
16    ) -> ErasedSegment {
17        SegmentBuilder::node(tables.next_id(), SyntaxKind::File, dialect, segments)
18            .position_from_segments()
19            .finish()
20    }
21
22    pub fn root_parse(
23        &self,
24        tables: &Tables,
25        dialect: DialectKind,
26        segments: &[ErasedSegment],
27        parse_context: &mut ParseContext,
28    ) -> Result<ErasedSegment, SQLParseError> {
29        let start_idx = segments
30            .iter()
31            .position(|segment| segment.is_code())
32            .unwrap_or(0) as u32;
33
34        let end_idx = segments
35            .iter()
36            .rposition(|segment| segment.is_code())
37            .map_or(start_idx, |idx| idx as u32 + 1);
38
39        if start_idx == end_idx {
40            return Ok(FileSegment::of(tables, dialect, segments.to_vec()));
41        }
42
43        let final_seg = segments.last().unwrap();
44        assert!(final_seg.get_position_marker().is_some());
45
46        let file_segment = parse_context.dialect().r#ref("FileSegment");
47
48        let match_result = file_segment
49            .match_grammar(parse_context.dialect())
50            .unwrap()
51            .match_segments(&segments[..end_idx as usize], start_idx, parse_context)?;
52
53        let match_span = match_result.span;
54        let has_match = match_result.has_match();
55        let mut matched = match_result.apply(tables, dialect, segments);
56        let unmatched = &segments[match_span.end as usize..end_idx as usize];
57
58        let content: &[ErasedSegment] = if !has_match {
59            &[SegmentBuilder::node(
60                tables.next_id(),
61                SyntaxKind::Unparsable,
62                dialect,
63                segments[start_idx as usize..end_idx as usize].to_vec(),
64            )
65            .position_from_segments()
66            .finish()]
67        } else if !unmatched.is_empty() {
68            let idx = unmatched
69                .iter()
70                .position(|it| it.is_code())
71                .unwrap_or(unmatched.len());
72            let (head, tail) = unmatched.split_at(idx);
73
74            matched.extend_from_slice(head);
75            matched.push(
76                SegmentBuilder::node(
77                    tables.next_id(),
78                    SyntaxKind::Unparsable,
79                    dialect,
80                    tail.to_vec(),
81                )
82                .position_from_segments()
83                .finish(),
84            );
85            &matched
86        } else {
87            matched.extend_from_slice(unmatched);
88            &matched
89        };
90
91        Ok(Self::of(
92            tables,
93            dialect,
94            [
95                &segments[..start_idx as usize],
96                content,
97                &segments[end_idx as usize..],
98            ]
99            .concat(),
100        ))
101    }
102}