dbml_language_server/analysis/
parser.rs1use super::token::{Token};
3use crate::ast::*;
4use chumsky::prelude::*;
5
6type ParseError = Simple<Token>;
7
8#[derive(Debug, Clone)]
9#[allow(dead_code)]
10pub enum Error {
11 LexError(Simple<char>),
12 ParseError(Simple<Token>),
13}
14
15pub fn parser() -> impl Parser<Token, Document, Error = ParseError> + Clone {
16 let ident = select! {
17 Token::Identifier(s) => s,
18 }
19 .map_with_span(|name, span| Ident { name, span });
20
21 let string_lit = select! {
22 Token::StringLiteral(s) => s,
23 }
24 .map_with_span(|value, span| StringLiteral { value, span });
25
26 let rel_type = choice((
28 just(Token::Minus).to(RelationshipType::OneToOne),
29 just(Token::Lt).to(RelationshipType::OneToMany),
30 just(Token::Gt).to(RelationshipType::ManyToOne),
31 just(Token::LtGt).to(RelationshipType::ManyToMany),
32 ));
33
34 let inline_ref = just(Token::Ref)
36 .ignore_then(just(Token::Colon))
37 .ignore_then(rel_type.clone())
38 .then(ident.clone())
39 .then_ignore(just(Token::Dot))
40 .then(ident.clone())
41 .map_with_span(|((relationship, target_table), target_column), span| {
42 InlineRef {
43 target_table,
44 target_column,
45 relationship,
46 span,
47 }
48 });
49
50 let column_setting = choice((
52 just(Token::Pk).to(ColumnSetting::PrimaryKey),
53 just(Token::NotNull).to(ColumnSetting::NotNull),
54 just(Token::Null).to(ColumnSetting::Null),
55 just(Token::Unique).to(ColumnSetting::Unique),
56 just(Token::Increment).to(ColumnSetting::Increment),
57 just(Token::Default)
58 .ignore_then(just(Token::Colon))
59 .ignore_then(select! {
60 Token::StringLiteral(s) => DefaultValue::String(s),
61 Token::NumericLiteral(n) => DefaultValue::Number(n),
62 Token::BoolLiteral(b) => DefaultValue::Boolean(b),
63 })
64 .map(ColumnSetting::Default),
65 just(Token::Note)
66 .ignore_then(just(Token::Colon))
67 .ignore_then(string_lit.clone())
68 .map(ColumnSetting::Note),
69 inline_ref.clone().map(ColumnSetting::Ref),
70 ));
71
72 let column_type = select! { Token::Identifier(s) => s }
74 .then(
75 just(Token::LParen)
77 .ignore_then(select! { Token::NumericLiteral(n) => n })
78 .then_ignore(just(Token::RParen))
79 .or_not()
80 )
81 .map(|(base_type, param)| match param {
82 Some(p) => format!("{}({})", base_type, p),
83 None => base_type,
84 });
85
86 let column = ident
87 .clone()
88 .then(column_type)
89 .then(
90 column_setting
91 .separated_by(just(Token::Comma))
92 .allow_trailing()
93 .delimited_by(just(Token::LBracket), just(Token::RBracket))
94 .or_not()
95 .map(|opt| opt.unwrap_or_default()),
96 )
97 .map_with_span(|((name, col_type), settings), span| Column {
98 name,
99 col_type,
100 settings,
101 span,
102 });
103
104 let index_column = ident.clone().map(IndexColumn::Simple);
106
107 let index_setting = choice((
108 just(Token::Pk).to(IndexSetting::PrimaryKey),
109 just(Token::Unique).to(IndexSetting::Unique),
110 ));
111
112 let index = just(Token::LParen)
113 .ignore_then(index_column.separated_by(just(Token::Comma)))
114 .then_ignore(just(Token::RParen))
115 .then(
116 index_setting
117 .separated_by(just(Token::Comma))
118 .allow_trailing()
119 .delimited_by(just(Token::LBracket), just(Token::RBracket))
120 .or_not()
121 .map(|opt| opt.unwrap_or_default()),
122 )
123 .map_with_span(|(columns, settings), span| Index {
124 columns,
125 settings,
126 span,
127 });
128
129 let indexes_block = just(Token::Indexes)
130 .ignore_then(
131 index
132 .repeated()
133 .at_least(1)
134 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
135 )
136 .map_with_span(|indexes, span| IndexesBlock { indexes, span });
137
138 let table_item = column
140 .map(TableItem::Column)
141 .or(indexes_block.map(TableItem::Indexes))
142 .or(just(Token::Note)
143 .ignore_then(just(Token::Colon))
144 .ignore_then(string_lit.clone())
145 .map(TableItem::Note));
146
147 let table = just(Token::Table)
149 .then(ident.clone())
150 .then(just(Token::As).ignore_then(ident.clone()).or_not())
151 .then(
152 table_item
153 .repeated()
154 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
155 )
156 .map_with_span(|(((_table_token, name), alias), items), span| Table {
157 name,
158 schema: None,
159 alias,
160 items,
161 settings: vec![],
162 span,
163 });
164
165 let ref_def = just(Token::Ref)
167 .ignore_then(ident.clone().or_not())
168 .then_ignore(just(Token::Colon))
169 .then(ident.clone())
170 .then_ignore(just(Token::Dot))
171 .then(ident.clone())
172 .then(rel_type.clone())
173 .then(ident.clone())
174 .then_ignore(just(Token::Dot))
175 .then(ident.clone())
176 .map_with_span(
177 |(((((name, from_table), from_col), relationship), to_table), to_col), span| Ref {
178 name,
179 from_table,
180 from_columns: vec![from_col],
181 to_table,
182 to_columns: vec![to_col],
183 relationship,
184 span,
185 },
186 );
187
188 let enum_member = ident
190 .clone()
191 .then(
192 just(Token::LBracket)
193 .ignore_then(just(Token::Note))
194 .ignore_then(just(Token::Colon))
195 .ignore_then(string_lit.clone())
196 .then_ignore(just(Token::RBracket))
197 .or_not(),
198 )
199 .map_with_span(|(name, note), span| EnumMember { name, note, span });
200
201 let enum_def = just(Token::Enum)
202 .ignore_then(ident.clone())
203 .then(
204 enum_member
205 .repeated()
206 .at_least(1)
207 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
208 )
209 .map_with_span(|(name, members), span| Enum {
210 name,
211 members,
212 span,
213 });
214
215 let project = just(Token::Project)
217 .ignore_then(ident.clone().or_not())
218 .then(
219 just(Token::LBrace)
220 .ignore_then(just(Token::RBrace))
221 .to(vec![]),
222 )
223 .map_with_span(|(name, settings), span| Project {
224 name,
225 settings,
226 span,
227 });
228
229 let document_item = table
231 .map(DocumentItem::Table)
232 .or(ref_def.map(DocumentItem::Ref))
233 .or(enum_def.map(DocumentItem::Enum))
234 .or(project.map(DocumentItem::Project));
235
236 document_item
237 .repeated()
238 .then_ignore(end())
239 .map_with_span(|items, span| Document { items, span })
240}
241
242pub fn parse(src: &str) -> Result<Document, Vec<Error>> {
243 use super::lexer::lexer;
244 use chumsky::Stream;
245
246 let tokens = lexer().parse(src).map_err(|errs| {
247 errs.into_iter().map(Error::LexError).collect::<Vec<_>>()
248 })?;
249
250 let token_spans: Vec<(Token, Span)> = tokens
252 .iter()
253 .map(|st| (st.token.clone(), st.span.clone()))
254 .collect();
255
256 let len = src.len();
257 let stream = Stream::from_iter(len..len+1, token_spans.into_iter());
258
259 parser().parse(stream).map_err(|errs| {
260 errs.into_iter().map(Error::ParseError).collect::<Vec<_>>()
261 })
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_parse_table() {
270 let input = r#"
271 Table users {
272 id int [pk]
273 name varchar
274 }
275 "#;
276 let result = parse(input);
277 assert!(result.is_ok());
278 }
279
280 #[test]
281 fn test_parse_enum() {
282 let input = r#"
283 Enum status {
284 active
285 inactive
286 }
287 "#;
288 let result = parse(input);
289 assert!(result.is_ok());
290 }
291}