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        _f_name: Option<String>,
29    ) -> Result<ErasedSegment, SQLParseError> {
30        let start_idx = segments
31            .iter()
32            .position(|segment| segment.is_code())
33            .unwrap_or(0) as u32;
34
35        let end_idx = segments
36            .iter()
37            .rposition(|segment| segment.is_code())
38            .map_or(start_idx, |idx| idx as u32 + 1);
39
40        if start_idx == end_idx {
41            return Ok(FileSegment::of(tables, dialect, segments.to_vec()));
42        }
43
44        let final_seg = segments.last().unwrap();
45        assert!(final_seg.get_position_marker().is_some());
46
47        let file_segment = parse_context.dialect().r#ref("FileSegment");
48
49        let match_result = file_segment
50            .match_grammar(parse_context.dialect())
51            .unwrap()
52            .match_segments(&segments[..end_idx as usize], start_idx, parse_context)?;
53
54        let match_span = match_result.span;
55        let has_match = match_result.has_match();
56        let mut matched = match_result.apply(tables, dialect, segments);
57        let unmatched = &segments[match_span.end as usize..end_idx as usize];
58
59        let content: &[ErasedSegment] = if !has_match {
60            &[SegmentBuilder::node(
61                tables.next_id(),
62                SyntaxKind::Unparsable,
63                dialect,
64                segments[start_idx as usize..end_idx as usize].to_vec(),
65            )
66            .position_from_segments()
67            .finish()]
68        } else if !unmatched.is_empty() {
69            let idx = unmatched
70                .iter()
71                .position(|it| it.is_code())
72                .unwrap_or(unmatched.len());
73            let (head, tail) = unmatched.split_at(idx);
74
75            matched.extend_from_slice(head);
76            matched.push(
77                SegmentBuilder::node(tables.next_id(), SyntaxKind::File, dialect, tail.to_vec())
78                    .position_from_segments()
79                    .finish(),
80            );
81            &matched
82        } else {
83            matched.extend_from_slice(unmatched);
84            &matched
85        };
86
87        Ok(Self::of(
88            tables,
89            dialect,
90            [
91                &segments[..start_idx as usize],
92                content,
93                &segments[end_idx as usize..],
94            ]
95            .concat(),
96        ))
97    }
98}