sqruff_lib_core/parser/segments/
file.rs1use 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}