sqruff_lib_core/
parser.rs1pub mod context;
2pub mod grammar;
3pub mod lexer;
4pub mod lookahead;
5pub mod markers;
6pub mod match_algorithms;
7pub mod match_result;
8pub mod matchable;
9pub mod node_matcher;
10pub mod parsers;
11pub mod segments;
12pub mod types;
13
14use crate::dialects::Dialect;
15use crate::errors::SQLParseError;
16use crate::parser::segments::file::FileSegment;
17use context::ParseContext;
18use segments::{ErasedSegment, Tables};
19
20#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
21pub struct IndentationConfig {
22 flags: u16,
23}
24
25impl IndentationConfig {
26 const INDENTED_JOINS_KEY: &'static str = "indented_joins";
27 const INDENTED_USING_ON_KEY: &'static str = "indented_using_on";
28 const INDENTED_ON_CONTENTS_KEY: &'static str = "indented_on_contents";
29 const INDENTED_THEN_KEY: &'static str = "indented_then";
30 const INDENTED_THEN_CONTENTS_KEY: &'static str = "indented_then_contents";
31 const INDENTED_JOINS_ON_KEY: &'static str = "indented_joins_on";
32 const INDENTED_CTES_KEY: &'static str = "indented_ctes";
33
34 pub const INDENTED_JOINS: Self = Self { flags: 1 << 0 };
35 pub const INDENTED_USING_ON: Self = Self { flags: 1 << 1 };
36 pub const INDENTED_ON_CONTENTS: Self = Self { flags: 1 << 2 };
37 pub const INDENTED_THEN: Self = Self { flags: 1 << 3 };
38 pub const INDENTED_THEN_CONTENTS: Self = Self { flags: 1 << 4 };
39 pub const INDENTED_JOINS_ON: Self = Self { flags: 1 << 5 };
40 pub const INDENTED_CTES: Self = Self { flags: 1 << 6 };
41
42 pub fn from_bool_lookup(mut get: impl FnMut(&str) -> bool) -> Self {
43 let mut config = Self::default();
44
45 config.insert_if(Self::INDENTED_JOINS, get(Self::INDENTED_JOINS_KEY));
46 config.insert_if(Self::INDENTED_USING_ON, get(Self::INDENTED_USING_ON_KEY));
47 config.insert_if(
48 Self::INDENTED_ON_CONTENTS,
49 get(Self::INDENTED_ON_CONTENTS_KEY),
50 );
51 config.insert_if(Self::INDENTED_THEN, get(Self::INDENTED_THEN_KEY));
52 config.insert_if(
53 Self::INDENTED_THEN_CONTENTS,
54 get(Self::INDENTED_THEN_CONTENTS_KEY),
55 );
56 config.insert_if(Self::INDENTED_JOINS_ON, get(Self::INDENTED_JOINS_ON_KEY));
57 config.insert_if(Self::INDENTED_CTES, get(Self::INDENTED_CTES_KEY));
58
59 config
60 }
61
62 pub fn contains(self, required: Self) -> bool {
63 (self.flags & required.flags) == required.flags
64 }
65
66 pub fn insert(&mut self, flag: Self) {
67 self.flags |= flag.flags;
68 }
69
70 pub fn insert_if(&mut self, flag: Self, enabled: bool) {
71 if enabled {
72 self.insert(flag);
73 }
74 }
75}
76
77#[derive(Clone)]
78pub struct Parser<'a> {
79 dialect: &'a Dialect,
80 pub(crate) indentation_config: IndentationConfig,
81}
82
83impl<'a> From<&'a Dialect> for Parser<'a> {
84 fn from(value: &'a Dialect) -> Self {
85 Self {
86 dialect: value,
87 indentation_config: IndentationConfig::default(),
88 }
89 }
90}
91
92impl<'a> Parser<'a> {
93 pub fn new(dialect: &'a Dialect, indentation_config: IndentationConfig) -> Self {
94 Self {
95 dialect,
96 indentation_config,
97 }
98 }
99
100 pub fn dialect(&self) -> &Dialect {
101 self.dialect
102 }
103
104 pub fn indentation_config(&self) -> IndentationConfig {
105 self.indentation_config
106 }
107
108 pub fn parse(
109 &self,
110 tables: &Tables,
111 segments: &[ErasedSegment],
112 ) -> Result<Option<ErasedSegment>, SQLParseError> {
113 if segments.is_empty() {
114 return Ok(None);
118 }
119
120 let mut parse_cx: ParseContext = self.into();
124
125 let root =
129 FileSegment.root_parse(tables, parse_cx.dialect().name, segments, &mut parse_cx)?;
130
131 #[cfg(debug_assertions)]
132 {
133 let join_segments_raw = |segments: &[ErasedSegment]| {
135 smol_str::SmolStr::from_iter(segments.iter().map(|s| s.raw().as_str()))
136 };
137
138 pretty_assertions::assert_eq!(&join_segments_raw(segments), root.raw());
139 }
140
141 Ok(root.into())
142 }
143}