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 ) -> 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}