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::base::{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.match_grammar().unwrap().match_segments(
50            &segments[..end_idx as usize],
51            start_idx,
52            parse_context,
53        )?;
54
55        let match_span = match_result.span;
56        let has_match = match_result.has_match();
57        let mut matched = match_result.apply(tables, dialect, segments);
58        let unmatched = &segments[match_span.end as usize..end_idx as usize];
59
60        let content: &[ErasedSegment] = if !has_match {
61            &[SegmentBuilder::node(
62                tables.next_id(),
63                SyntaxKind::Unparsable,
64                dialect,
65                segments[start_idx as usize..end_idx as usize].to_vec(),
66            )
67            .position_from_segments()
68            .finish()]
69        } else if !unmatched.is_empty() {
70            let idx = unmatched
71                .iter()
72                .position(|it| it.is_code())
73                .unwrap_or(unmatched.len());
74            let (head, tail) = unmatched.split_at(idx);
75
76            matched.extend_from_slice(head);
77            matched.push(
78                SegmentBuilder::node(tables.next_id(), SyntaxKind::File, dialect, tail.to_vec())
79                    .position_from_segments()
80                    .finish(),
81            );
82            &matched
83        } else {
84            matched.extend_from_slice(unmatched);
85            &matched
86        };
87
88        Ok(Self::of(
89            tables,
90            dialect,
91            [
92                &segments[..start_idx as usize],
93                content,
94                &segments[end_idx as usize..],
95            ]
96            .concat(),
97        ))
98    }
99}