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 ref_action = choice((
36 just(Token::Cascade).to(ReferentialAction::Cascade),
37 just(Token::Restrict).to(ReferentialAction::Restrict),
38 just(Token::NoAction).to(ReferentialAction::NoAction),
39 just(Token::SetNull).to(ReferentialAction::SetNull),
40 just(Token::SetDefault).to(ReferentialAction::SetDefault),
41 ));
42
43 let inline_ref = just(Token::Ref)
45 .ignore_then(just(Token::Colon))
46 .ignore_then(rel_type.clone())
47 .then(ident.clone())
48 .then_ignore(just(Token::Dot))
49 .then(ident.clone())
50 .map_with_span(|((relationship, target_table), target_column), span| {
51 InlineRef {
52 target_table,
53 target_column,
54 relationship,
55 span,
56 }
57 });
58
59 let column_setting = choice((
61 just(Token::Pk).to(ColumnSetting::PrimaryKey),
62 just(Token::NotNull).to(ColumnSetting::NotNull),
63 just(Token::Null).to(ColumnSetting::Null),
64 just(Token::Unique).to(ColumnSetting::Unique),
65 just(Token::Increment).to(ColumnSetting::Increment),
66 just(Token::Default)
67 .ignore_then(just(Token::Colon))
68 .ignore_then(select! {
69 Token::StringLiteral(s) => DefaultValue::String(s),
70 Token::NumericLiteral(n) => DefaultValue::Number(n),
71 Token::BoolLiteral(b) => DefaultValue::Boolean(b),
72 })
73 .map(ColumnSetting::Default),
74 just(Token::Note)
75 .ignore_then(just(Token::Colon))
76 .ignore_then(string_lit.clone())
77 .map(ColumnSetting::Note),
78 inline_ref.clone().map(ColumnSetting::Ref),
79 ));
80
81 let column_type = select! { Token::Identifier(s) => s }
83 .then(
84 just(Token::LParen)
86 .ignore_then(select! { Token::NumericLiteral(n) => n })
87 .then_ignore(just(Token::RParen))
88 .or_not()
89 )
90 .map(|(base_type, param)| match param {
91 Some(p) => format!("{}({})", base_type, p),
92 None => base_type,
93 })
94 .map_with_span(|type_str, span| (type_str, span));
95
96 let column = ident
97 .clone()
98 .then(column_type)
99 .then(
100 column_setting
101 .separated_by(just(Token::Comma))
102 .allow_trailing()
103 .delimited_by(just(Token::LBracket), just(Token::RBracket))
104 .or_not()
105 .map(|opt| opt.unwrap_or_default()),
106 )
107 .map_with_span(|((name, (col_type, col_type_span)), settings), span| Column {
108 name,
109 col_type,
110 col_type_span,
111 settings,
112 span,
113 });
114
115 let index_column = ident.clone().map(IndexColumn::Simple);
117
118 let index_setting = choice((
119 just(Token::Pk).to(IndexSetting::PrimaryKey),
120 just(Token::Unique).to(IndexSetting::Unique),
121 ));
122
123 let index = just(Token::LParen)
124 .ignore_then(index_column.separated_by(just(Token::Comma)))
125 .then_ignore(just(Token::RParen))
126 .then(
127 index_setting
128 .separated_by(just(Token::Comma))
129 .allow_trailing()
130 .delimited_by(just(Token::LBracket), just(Token::RBracket))
131 .or_not()
132 .map(|opt| opt.unwrap_or_default()),
133 )
134 .map_with_span(|(columns, settings), span| Index {
135 columns,
136 settings,
137 span,
138 });
139
140 let indexes_block = just(Token::Indexes)
141 .ignore_then(
142 index
143 .repeated()
144 .at_least(1)
145 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
146 )
147 .map_with_span(|indexes, span| IndexesBlock { indexes, span });
148
149 let table_item = column
151 .map(TableItem::Column)
152 .or(indexes_block.map(TableItem::Indexes))
153 .or(just(Token::Note)
154 .ignore_then(just(Token::Colon))
155 .ignore_then(string_lit.clone())
156 .map(TableItem::Note));
157
158 let table = just(Token::Table)
160 .then(ident.clone())
161 .then(just(Token::As).ignore_then(ident.clone()).or_not())
162 .then(
163 table_item
164 .repeated()
165 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
166 )
167 .map_with_span(|(((_table_token, name), alias), items), span| Table {
168 name,
169 schema: None,
170 alias,
171 items,
172 settings: vec![],
173 span,
174 });
175
176 let delete_setting = just(Token::Delete)
179 .ignore_then(just(Token::Colon))
180 .ignore_then(ref_action.clone())
181 .map(|action| ("delete", action));
182
183 let update_setting = just(Token::Update)
184 .ignore_then(just(Token::Colon))
185 .ignore_then(ref_action.clone())
186 .map(|action| ("update", action));
187
188 let ref_settings_block = delete_setting
189 .or(update_setting)
190 .separated_by(just(Token::Comma))
191 .at_least(1)
192 .delimited_by(just(Token::LBracket), just(Token::RBracket))
193 .map(|settings: Vec<(&str, ReferentialAction)>| {
194 let mut on_delete = None;
195 let mut on_update = None;
196 for (key, action) in settings {
197 match key {
198 "delete" => on_delete = Some(action),
199 "update" => on_update = Some(action),
200 _ => {}
201 }
202 }
203 (on_delete, on_update)
204 });
205
206 let ref_def = just(Token::Ref)
207 .ignore_then(ident.clone().or_not())
208 .then_ignore(just(Token::Colon))
209 .then(ident.clone())
210 .then_ignore(just(Token::Dot))
211 .then(ident.clone())
212 .then(rel_type.clone())
213 .then(ident.clone())
214 .then_ignore(just(Token::Dot))
215 .then(ident.clone())
216 .then(ref_settings_block.or_not())
217 .map_with_span(
218 |((((((name, from_table), from_col), relationship), to_table), to_col), settings), span| {
219 let (on_delete, on_update) = settings.unwrap_or((None, None));
220 Ref {
221 name,
222 from_table,
223 from_columns: vec![from_col],
224 to_table,
225 to_columns: vec![to_col],
226 relationship,
227 on_delete,
228 on_update,
229 span,
230 }
231 },
232 );
233
234 let enum_member = ident
236 .clone()
237 .then(
238 just(Token::LBracket)
239 .ignore_then(just(Token::Note))
240 .ignore_then(just(Token::Colon))
241 .ignore_then(string_lit.clone())
242 .then_ignore(just(Token::RBracket))
243 .or_not(),
244 )
245 .map_with_span(|(name, note), span| EnumMember { name, note, span });
246
247 let enum_def = just(Token::Enum)
248 .ignore_then(ident.clone())
249 .then(
250 enum_member
251 .repeated()
252 .at_least(1)
253 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
254 )
255 .map_with_span(|(name, members), span| Enum {
256 name,
257 members,
258 span,
259 });
260
261 let project_setting = just(Token::Note)
263 .ignore_then(just(Token::Colon))
264 .ignore_then(string_lit.clone())
265 .map(|note| crate::ast::ProjectSetting::Note(note))
266 .or(ident.clone()
267 .then_ignore(just(Token::Colon))
268 .then(string_lit.clone())
269 .map(|(key, value)| {
270 if key.name.to_lowercase() == "database_type" {
271 crate::ast::ProjectSetting::DatabaseType(value.value)
272 } else {
273 crate::ast::ProjectSetting::DatabaseType(format!("{}: {}", key.name, value.value))
276 }
277 })
278 );
279
280 let project = just(Token::Project)
281 .ignore_then(ident.clone().or_not())
282 .then(
283 project_setting
284 .repeated()
285 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
286 )
287 .map_with_span(|(name, settings), span| Project {
288 name,
289 settings,
290 span,
291 });
292
293 let document_item = table
295 .map(DocumentItem::Table)
296 .or(ref_def.map(DocumentItem::Ref))
297 .or(enum_def.map(DocumentItem::Enum))
298 .or(project.map(DocumentItem::Project));
299
300 document_item
301 .repeated()
302 .then_ignore(end())
303 .map_with_span(|items, span| Document { items, span })
304}
305
306pub fn parse(src: &str) -> Result<Document, Vec<Error>> {
307 use super::lexer::lexer;
308 use chumsky::Stream;
309
310 let tokens = lexer().parse(src).map_err(|errs| {
311 errs.into_iter().map(Error::LexError).collect::<Vec<_>>()
312 })?;
313
314 let token_spans: Vec<(Token, Span)> = tokens
316 .iter()
317 .map(|st| (st.token.clone(), st.span.clone()))
318 .collect();
319
320 let len = src.len();
321 let stream = Stream::from_iter(len..len+1, token_spans.into_iter());
322
323 parser().parse(stream).map_err(|errs| {
324 errs.into_iter().map(Error::ParseError).collect::<Vec<_>>()
325 })
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 #[test]
333 fn test_parse_table() {
334 let input = r#"
335 Table users {
336 id int [pk]
337 name varchar
338 }
339 "#;
340 let result = parse(input);
341 assert!(result.is_ok());
342 }
343
344 #[test]
345 fn test_parse_enum() {
346 let input = r#"
347 Enum status {
348 active
349 inactive
350 }
351 "#;
352 let result = parse(input);
353 assert!(result.is_ok());
354 }
355}