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::{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}