Skip to main content

dbml_rs/parser/
mod.rs

1mod err;
2mod helper;
3
4use alloc::string::{
5  String,
6  ToString,
7};
8use alloc::vec::Vec;
9use core::str::FromStr;
10
11use err::*;
12use pest::Parser;
13use pest::iterators::Pair;
14
15use self::helper::*;
16use crate::ast::*;
17
18#[derive(Parser)]
19#[grammar = "src/dbml.pest"]
20struct DBMLParser;
21
22/// Parses the entire DBML text and returns an unsanitized Abstract Syntax Tree (AST).
23///
24/// # Arguments
25///
26/// * `input` - A string slice containing the DBML text to parse.
27///
28/// # Returns
29///
30/// A `ParserResult<SchemaBlock>`, which is an alias for `pest`'s `ParseResult` type
31/// representing the result of parsing. It contains the unsanitized abstract syntax tree (AST)
32/// representing the parsed DBML.
33///
34/// # Errors
35///
36/// This function can return parsing errors if the input text does not conform to the DBML grammar.
37/// It may also panic if an unexpected parsing rule is encountered, which should be considered a
38/// bug.
39///
40/// # Examples
41///
42/// ```rs
43/// use dbml_rs::parse_dbml_unchecked;
44///
45/// let dbml_text = r#"
46///     Table users {
47///         id int
48///         username varchar
49///     }
50/// "#;
51///
52/// let result = parse_dbml_unchecked(dbml_text);
53/// assert!(result.is_ok());
54/// let ast = result.unwrap();
55/// // Now `ast` contains the unsanitized abstract syntax tree (AST) of the parsed DBML text.
56/// ```
57pub fn parse(input: &str) -> ParserResult<SchemaBlock<'_>> {
58  let pair = DBMLParser::parse(Rule::schema, input)?
59    .next()
60    .ok_or_else(|| unreachable!("unhandled parsing error"))?;
61
62  match pair.as_rule() {
63    Rule::schema => Ok(parse_schema(pair, input)?),
64    _ => throw_rules(&[Rule::schema], pair)?,
65  }
66}
67
68fn parse_schema<'a>(pair: Pair<Rule>, input: &'a str) -> ParserResult<SchemaBlock<'a>> {
69  let init = SchemaBlock {
70    span_range: s2r(pair.as_span()),
71    input,
72    ..Default::default()
73  };
74
75  pair.into_inner().try_fold(init, |mut acc, p1| {
76    match p1.as_rule() {
77      Rule::project_decl => acc.blocks.push(TopLevelBlock::Project(parse_project_decl(p1)?)),
78      Rule::table_decl => acc.blocks.push(TopLevelBlock::Table(parse_table_decl(p1)?)),
79      Rule::enum_decl => acc.blocks.push(TopLevelBlock::Enum(parse_enum_decl(p1)?)),
80      Rule::ref_decl => acc.blocks.push(TopLevelBlock::Ref(parse_ref_decl(p1)?)),
81      Rule::note_decl => acc.blocks.push(TopLevelBlock::Note(parse_note_decl(p1)?)),
82      Rule::table_group_decl => acc.blocks.push(TopLevelBlock::TableGroup(parse_table_group_decl(p1)?)),
83      Rule::EOI => (),
84      _ => {
85        throw_rules(
86          &[
87            Rule::project_decl,
88            Rule::table_decl,
89            Rule::enum_decl,
90            Rule::ref_decl,
91            Rule::note_block,
92            Rule::table_group_decl,
93          ],
94          p1,
95        )?
96      }
97    };
98
99    Ok(acc)
100  })
101}
102
103fn parse_project_decl(pair: Pair<Rule>) -> ParserResult<ProjectBlock> {
104  let init = ProjectBlock {
105    span_range: s2r(pair.as_span()),
106    ..Default::default()
107  };
108
109  pair.into_inner().try_fold(init, |mut acc, p1| {
110    match p1.as_rule() {
111      Rule::ident => acc.ident = parse_ident(p1)?,
112      Rule::project_block => {
113        for p2 in p1.into_inner() {
114          match p2.as_rule() {
115            Rule::property => {
116              let prop = parse_property(p2.clone())?;
117
118              match prop.key.to_string.as_str() {
119                "database_type" => {
120                  if let Value::String(db_name) = prop.value.value.clone() {
121                    acc.database_type = match DatabaseType::from_str(&db_name) {
122                      Ok(val) => Some(val),
123                      Err(msg) => throw_msg(msg, p2)?,
124                    }
125                  }
126                }
127                _ => (),
128              }
129
130              acc.properties.push(prop)
131            }
132            Rule::note_decl => acc.note = Some(parse_note_decl(p2)?),
133            _ => throw_rules(&[Rule::property, Rule::note_decl], p2)?,
134          };
135        }
136      }
137      _ => throw_rules(&[Rule::project_block], p1)?,
138    }
139
140    Ok(acc)
141  })
142}
143
144fn parse_table_decl(pair: Pair<Rule>) -> ParserResult<TableBlock> {
145  let init = TableBlock {
146    span_range: s2r(pair.as_span()),
147    ..Default::default()
148  };
149
150  pair.into_inner().try_fold(init, |mut acc, p1| {
151    match p1.as_rule() {
152      Rule::decl_ident => {
153        acc.ident.span_range = s2r(p1.as_span());
154
155        let (schema, name) = parse_decl_ident(p1)?;
156
157        acc.ident.name = name;
158        acc.ident.schema = schema;
159      }
160      Rule::table_alias => {
161        for p2 in p1.into_inner() {
162          match p2.as_rule() {
163            Rule::ident => acc.ident.alias = Some(parse_ident(p2)?),
164            _ => throw_rules(&[Rule::ident], p2)?,
165          }
166        }
167      }
168      Rule::table_block => {
169        for p2 in p1.into_inner() {
170          match p2.as_rule() {
171            Rule::table_col => acc.cols.push(parse_table_col(p2)?),
172            Rule::note_decl => acc.note = Some(parse_note_decl(p2)?),
173            Rule::indexes_decl => acc.indexes = Some(parse_indexes_decl(p2)?),
174            _ => throw_rules(&[Rule::table_col, Rule::note_decl, Rule::indexes_decl], p2)?,
175          }
176        }
177      }
178      Rule::block_settings => {
179        acc.settings = Some(parse_table_settings(p1)?);
180      }
181      _ => {
182        throw_rules(
183          &[
184            Rule::decl_ident,
185            Rule::table_alias,
186            Rule::table_block,
187            Rule::block_settings,
188          ],
189          p1,
190        )?
191      }
192    }
193
194    Ok(acc)
195  })
196}
197
198fn parse_table_settings(pair: Pair<Rule>) -> ParserResult<TableSettings> {
199  Ok(TableSettings {
200    span_range: s2r(pair.as_span()),
201    attributes: pair
202      .into_inner()
203      .map(|p1| {
204        match p1.as_rule() {
205          Rule::attribute => parse_attribute(p1),
206          _ => throw_rules(&[Rule::attribute], p1),
207        }
208      })
209      .collect::<ParserResult<_>>()?,
210  })
211}
212
213fn parse_table_col(pair: Pair<Rule>) -> ParserResult<TableColumn> {
214  let init = TableColumn {
215    span_range: s2r(pair.as_span()),
216    ..Default::default()
217  };
218
219  pair.into_inner().try_fold(init, |mut acc, p1| {
220    match p1.as_rule() {
221      Rule::ident => acc.name = parse_ident(p1)?,
222      Rule::col_type => {
223        acc.r#type = parse_col_type(p1)?;
224      }
225      Rule::col_settings => acc.settings = Some(parse_col_settings(p1)?),
226      _ => throw_rules(&[Rule::ident, Rule::col_type, Rule::col_settings], p1)?,
227    }
228
229    Ok(acc)
230  })
231}
232
233fn build_type_name_with_schema(schema: Option<&Ident>, type_name: Pair<Rule>) -> String {
234  let mut type_name = type_name.as_str().to_string();
235  if let Some(schema) = schema {
236    type_name = format!("{}.{}", schema.to_string, type_name);
237  }
238  type_name
239}
240
241fn parse_col_type(pair: Pair<Rule>) -> ParserResult<ColumnType> {
242  let mut out = ColumnType {
243    span_range: s2r(pair.as_span()),
244    raw: pair.as_str().to_string(),
245    ..Default::default()
246  };
247
248  let mut schema = None;
249
250  for p1 in pair.into_inner() {
251    match p1.as_rule() {
252      Rule::ident => {
253        schema = Some(parse_ident(p1)?);
254      }
255      Rule::col_type_quoted | Rule::col_type_unquoted => {
256        for p2 in p1.into_inner() {
257          match p2.as_rule() {
258            Rule::var | Rule::spaced_var => {
259              out.type_name = ColumnTypeName::Raw(build_type_name_with_schema(schema.as_ref(), p2))
260            }
261            Rule::col_type_arg => out.args = parse_col_type_arg(p2)?,
262            Rule::col_type_array => {
263              let val = p2.into_inner().try_fold(None, |_, p3| {
264                match p3.as_rule() {
265                  Rule::integer => {
266                    let val = match p3.as_str().parse::<u32>() {
267                      Ok(val) => Some(val),
268                      Err(err) => throw_msg(err.to_string(), p3)?,
269                    };
270
271                    Ok(val)
272                  }
273                  _ => throw_rules(&[Rule::integer], p3)?,
274                }
275              })?;
276
277              out.arrays.push(val)
278            }
279            _ => {
280              throw_rules(
281                &[Rule::var, Rule::spaced_var, Rule::col_type_arg, Rule::col_type_array],
282                p2,
283              )?
284            }
285          }
286        }
287      }
288      _ => throw_rules(&[Rule::col_type_quoted, Rule::col_type_unquoted], p1)?,
289    }
290  }
291
292  Ok(out)
293}
294
295fn parse_col_type_arg(pair: Pair<Rule>) -> ParserResult<Vec<Value>> {
296  pair.into_inner().try_fold(vec![], |mut acc, p1| {
297    match p1.as_rule() {
298      Rule::value => acc.push(parse_value(p1)?),
299      _ => throw_rules(&[Rule::value], p1)?,
300    }
301
302    Ok(acc)
303  })
304}
305
306fn parse_col_settings(pair: Pair<Rule>) -> ParserResult<ColumnSettings> {
307  let init = ColumnSettings {
308    span_range: s2r(pair.as_span()),
309    ..Default::default()
310  };
311
312  pair.into_inner().try_fold(init, |mut acc, p1| {
313    match p1.as_rule() {
314      Rule::col_attribute => {
315        for p2 in p1.into_inner() {
316          match p2.as_rule() {
317            Rule::attribute => {
318              let attr = parse_attribute(p2)?;
319
320              match attr.key.to_string.as_str() {
321                "unique" => acc.is_unique = true,
322                "primary key" | "pk" => acc.is_pk = true,
323                "null" => acc.nullable = Some(Nullable::Null),
324                "not null" => acc.nullable = Some(Nullable::NotNull),
325                "increment" => acc.is_incremental = true,
326                "default" => acc.default = attr.value.clone().map(|v| v.value),
327                "note" => acc.note = attr.value.clone().map(|v| v.value.to_string()),
328                _ => (),
329              }
330
331              acc.attributes.push(attr);
332            }
333            Rule::ref_inline => acc.refs.push(parse_ref_inline(p2)?),
334            _ => throw_rules(&[Rule::ref_inline, Rule::attribute], p2)?,
335          }
336        }
337      }
338      _ => throw_rules(&[Rule::col_attribute], p1)?,
339    }
340
341    Ok(acc)
342  })
343}
344
345fn parse_enum_decl(pair: Pair<Rule>) -> ParserResult<EnumBlock> {
346  let init = EnumBlock {
347    span_range: s2r(pair.as_span()),
348    ..Default::default()
349  };
350
351  pair.into_inner().try_fold(init, |mut acc, p1| {
352    match p1.as_rule() {
353      Rule::decl_ident => {
354        acc.ident.span_range = s2r(p1.as_span());
355
356        let (schema, name) = parse_decl_ident(p1)?;
357
358        acc.ident.schema = schema;
359        acc.ident.name = name;
360      }
361      Rule::enum_block => acc.values = parse_enum_block(p1)?,
362      _ => throw_rules(&[Rule::decl_ident, Rule::enum_block], p1)?,
363    }
364
365    Ok(acc)
366  })
367}
368
369fn parse_enum_block(pair: Pair<Rule>) -> ParserResult<Vec<EnumValue>> {
370  pair
371    .into_inner()
372    .map(|p1| {
373      match p1.as_rule() {
374        Rule::enum_value => Ok(parse_enum_value(p1)?),
375        _ => throw_rules(&[Rule::enum_value], p1)?,
376      }
377    })
378    .collect()
379}
380
381fn parse_enum_value(pair: Pair<Rule>) -> ParserResult<EnumValue> {
382  let init = EnumValue {
383    span_range: s2r(pair.as_span()),
384    ..Default::default()
385  };
386
387  pair.into_inner().try_fold(init, |mut acc, p1| {
388    match p1.as_rule() {
389      Rule::ident => acc.value = parse_ident(p1)?,
390      Rule::enum_settings => {
391        let mut settings = EnumValueSettings {
392          span_range: s2r(p1.as_span()),
393          ..Default::default()
394        };
395
396        for p2 in p1.into_inner() {
397          match p2.as_rule() {
398            Rule::attribute => {
399              let attr = parse_attribute(p2)?;
400
401              match attr.key.to_string.as_str() {
402                "note" => settings.note = attr.value.clone().map(|v| v.value.to_string()),
403                _ => (),
404              }
405
406              settings.attributes.push(attr);
407            }
408            _ => throw_rules(&[Rule::attribute], p2)?,
409          }
410        }
411
412        acc.settings = Some(settings);
413      }
414      _ => throw_rules(&[Rule::ident, Rule::enum_settings], p1)?,
415    }
416
417    Ok(acc)
418  })
419}
420
421fn parse_ref_decl(pair: Pair<Rule>) -> ParserResult<RefBlock> {
422  for p1 in pair.into_inner() {
423    match p1.as_rule() {
424      Rule::ref_block | Rule::ref_short => {
425        let mut name = None;
426
427        for p2 in p1.into_inner() {
428          match p2.as_rule() {
429            Rule::ref_stmt => {
430              return parse_ref_stmt(p2).map(|mut o| {
431                o.name = name;
432                o
433              });
434            }
435            Rule::ident => {
436              name = Some(parse_ident(p2)?);
437            }
438            _ => throw_rules(&[Rule::ref_stmt, Rule::ident], p2)?,
439          }
440        }
441      }
442      _ => throw_rules(&[Rule::ref_block, Rule::ref_short], p1)?,
443    }
444  }
445
446  unreachable!("something went wrong parsing ref_decl")
447}
448
449fn parse_ref_stmt(pair: Pair<Rule>) -> ParserResult<RefBlock> {
450  let init = RefBlock {
451    span_range: s2r(pair.as_span()),
452    ..Default::default()
453  };
454
455  pair.into_inner().try_fold(init, |mut acc, p1| {
456    match p1.as_rule() {
457      Rule::relation => {
458        acc.rel = match Relation::from_str(p1.as_str()) {
459          Ok(rel) => rel,
460          Err(err) => throw_msg(err, p1)?,
461        }
462      }
463      Rule::ref_ident => {
464        let value = parse_ref_ident(p1)?;
465
466        if acc.rel == Relation::Undef {
467          acc.lhs = value;
468        } else {
469          acc.rhs = value;
470        }
471      }
472      Rule::rel_settings => acc.settings = Some(parse_rel_settings(p1)?),
473      _ => throw_rules(&[Rule::relation, Rule::ref_ident, Rule::rel_settings], p1)?,
474    }
475
476    Ok(acc)
477  })
478}
479
480fn parse_ref_inline(pair: Pair<Rule>) -> ParserResult<RefInline> {
481  let init = RefInline {
482    span_range: s2r(pair.as_span()),
483    ..Default::default()
484  };
485
486  pair.into_inner().try_fold(init, |mut acc, p1| {
487    match p1.as_rule() {
488      Rule::relation => {
489        acc.rel = match Relation::from_str(p1.as_str()) {
490          Ok(rel) => rel,
491          Err(err) => throw_msg(err, p1)?,
492        }
493      }
494      Rule::ref_ident => {
495        acc.rhs = parse_ref_ident(p1)?;
496      }
497      _ => throw_rules(&[Rule::relation, Rule::ref_ident], p1)?,
498    }
499
500    Ok(acc)
501  })
502}
503
504fn parse_ref_ident(pair: Pair<Rule>) -> ParserResult<RefIdent> {
505  let mut out = RefIdent {
506    span_range: s2r(pair.as_span()),
507    ..Default::default()
508  };
509  let mut tmp_tokens = vec![];
510
511  for p1 in pair.into_inner() {
512    match p1.as_rule() {
513      Rule::ident => tmp_tokens.push(parse_ident(p1)?),
514      Rule::ref_composition => {
515        for p2 in p1.into_inner() {
516          match p2.as_rule() {
517            Rule::ident => out.compositions.push(parse_ident(p2)?),
518            _ => throw_rules(&[Rule::ident], p2)?,
519          }
520        }
521      }
522      _ => throw_rules(&[Rule::ident, Rule::ref_composition], p1)?,
523    }
524  }
525
526  match tmp_tokens.len() {
527    1 => out.table = tmp_tokens.remove(0),
528    2 => {
529      out.schema = Some(tmp_tokens.remove(0));
530      out.table = tmp_tokens.remove(0);
531    }
532    _ => unreachable!("unwell formatted ident"),
533  }
534
535  Ok(out)
536}
537
538fn parse_table_group_decl(pair: Pair<Rule>) -> ParserResult<TableGroupBlock> {
539  let init = TableGroupBlock {
540    span_range: s2r(pair.as_span()),
541    ..Default::default()
542  };
543
544  pair.into_inner().try_fold(init, |mut acc, p1| {
545    match p1.as_rule() {
546      Rule::ident => acc.ident = parse_ident(p1)?,
547      Rule::table_group_block => {
548        for p2 in p1.into_inner() {
549          let mut init = TableGroupItem {
550            span_range: s2r(p2.as_span()),
551            ..Default::default()
552          };
553
554          match p2.as_rule() {
555            Rule::decl_ident => {
556              let (schema, name) = parse_decl_ident(p2)?;
557
558              init.schema = schema;
559              init.ident_alias = name;
560
561              acc.items.push(init)
562            }
563            Rule::note_decl => acc.note = Some(parse_note_decl(p2)?),
564            _ => throw_rules(&[Rule::decl_ident, Rule::note_decl], p2)?,
565          }
566        }
567      }
568      Rule::block_settings => {
569        acc.settings = Some(parse_table_group_settings(p1)?);
570      }
571      _ => throw_rules(&[Rule::ident, Rule::table_group_block, Rule::block_settings], p1)?,
572    }
573
574    Ok(acc)
575  })
576}
577
578fn parse_table_group_settings(pair: Pair<Rule>) -> ParserResult<TableGroupSettings> {
579  Ok(TableGroupSettings {
580    span_range: s2r(pair.as_span()),
581    attributes: pair
582      .into_inner()
583      .map(|p1| {
584        match p1.as_rule() {
585          Rule::attribute => parse_attribute(p1),
586          _ => throw_rules(&[Rule::attribute], p1),
587        }
588      })
589      .collect::<ParserResult<_>>()?,
590  })
591}
592
593fn parse_rel_settings(pair: Pair<Rule>) -> ParserResult<RefSettings> {
594  let init = RefSettings {
595    span_range: s2r(pair.as_span()),
596    ..Default::default()
597  };
598
599  pair.into_inner().try_fold(init, |mut acc, p1| {
600    match p1.as_rule() {
601      Rule::attribute => {
602        let attr = parse_attribute(p1.clone())?;
603
604        match attr.key.to_string.as_str() {
605          "update" => {
606            acc.on_update = match &attr.value {
607              Some(Literal {
608                value: Value::Enum(value),
609                ..
610              }) => {
611                match ReferentialAction::from_str(value) {
612                  Ok(value) => Some(value),
613                  Err(msg) => throw_msg(msg, p1)?,
614                }
615              }
616              _ => None,
617            }
618          }
619          "delete" => {
620            acc.on_delete = match &attr.value {
621              Some(Literal {
622                value: Value::Enum(value),
623                ..
624              }) => {
625                match ReferentialAction::from_str(value) {
626                  Ok(value) => Some(value),
627                  Err(msg) => throw_msg(msg, p1)?,
628                }
629              }
630              _ => None,
631            }
632          }
633          _ => (),
634        }
635
636        acc.attributes.push(attr);
637      }
638      _ => throw_rules(&[Rule::attribute], p1)?,
639    }
640
641    Ok(acc)
642  })
643}
644
645fn parse_note_decl(pair: Pair<Rule>) -> ParserResult<NoteBlock> {
646  for p1 in pair.into_inner() {
647    match p1.as_rule() {
648      Rule::note_short | Rule::note_block => {
649        for p2 in p1.clone().into_inner() {
650          match p2.as_rule() {
651            Rule::string_value => {
652              return parse_string_value(p2.clone()).map(|value| {
653                NoteBlock {
654                  span_range: s2r(p1.as_span()),
655                  value: Literal {
656                    span_range: s2r(p2.as_span()),
657                    raw: p2.as_str().to_string(),
658                    value: Value::String(value),
659                  },
660                }
661              });
662            }
663            _ => throw_rules(&[Rule::string_value], p2)?,
664          }
665        }
666      }
667      _ => throw_rules(&[Rule::note_short, Rule::note_block], p1)?,
668    }
669  }
670
671  unreachable!("something went wrong parsing note_decl")
672}
673
674fn parse_indexes_decl(pair: Pair<Rule>) -> ParserResult<IndexesBlock> {
675  let p1 = pair
676    .into_inner()
677    .next()
678    .ok_or_else(|| unreachable!("something went wrong parsing indexes_decl"))?;
679
680  match p1.as_rule() {
681    Rule::indexes_block => parse_indexes_block(p1),
682    _ => throw_rules(&[Rule::indexes_block], p1)?,
683  }
684}
685
686fn parse_indexes_block(pair: Pair<Rule>) -> ParserResult<IndexesBlock> {
687  let init = IndexesBlock {
688    span_range: s2r(pair.as_span()),
689    ..Default::default()
690  };
691
692  pair.into_inner().try_fold(init, |mut acc, p1| {
693    match p1.as_rule() {
694      Rule::indexes_single | Rule::indexes_multi => acc.defs.push(parse_indexes_single_multi(p1)?),
695      _ => throw_rules(&[Rule::indexes_single, Rule::indexes_multi], p1)?,
696    }
697
698    Ok(acc)
699  })
700}
701
702fn parse_indexes_single_multi(pair: Pair<Rule>) -> ParserResult<IndexesDef> {
703  let init = IndexesDef {
704    span_range: s2r(pair.as_span()),
705    ..Default::default()
706  };
707
708  pair.into_inner().try_fold(init, |mut acc, p1| {
709    match p1.as_rule() {
710      Rule::indexes_ident => acc.cols.push(parse_indexes_ident(p1)?),
711      Rule::indexes_settings => acc.settings = Some(parse_indexes_settings(p1)?),
712      _ => throw_rules(&[Rule::indexes_ident, Rule::indexes_settings], p1)?,
713    }
714
715    Ok(acc)
716  })
717}
718
719fn parse_indexes_ident(pair: Pair<Rule>) -> ParserResult<IndexesColumnType> {
720  let p1 = pair
721    .into_inner()
722    .next()
723    .ok_or_else(|| unreachable!("something went wrong at indexes_ident"))?;
724
725  match p1.as_rule() {
726    Rule::ident => {
727      let value = parse_ident(p1)?;
728      Ok(IndexesColumnType::String(value))
729    }
730    Rule::backquoted_quoted_string => {
731      let p2 = p1
732        .clone()
733        .into_inner()
734        .next()
735        .ok_or_else(|| unreachable!("something went wrong at indexes_ident"))?;
736
737      match p2.as_rule() {
738        Rule::backquoted_quoted_value => {
739          Ok(IndexesColumnType::Expr(Literal {
740            span_range: s2r(p1.as_span()),
741            raw: p1.as_str().to_string(),
742            value: Value::String(p2.as_str().to_string()),
743          }))
744        }
745        _ => throw_rules(&[Rule::backquoted_quoted_value], p2)?,
746      }
747    }
748    _ => throw_rules(&[Rule::ident, Rule::backquoted_quoted_string], p1)?,
749  }
750}
751
752fn parse_indexes_settings(pair: Pair<Rule>) -> ParserResult<IndexesSettings> {
753  let init = IndexesSettings {
754    span_range: s2r(pair.as_span()),
755    ..Default::default()
756  };
757
758  pair.into_inner().try_fold(init, |mut acc, p1| {
759    match p1.as_rule() {
760      Rule::attribute => {
761        let attr = parse_attribute(p1.clone())?;
762
763        match attr.key.to_string.as_str() {
764          "unique" => acc.is_unique = true,
765          "pk" => acc.is_pk = true,
766          "type" => {
767            acc.r#type = match attr.value.clone().map(|v| IndexesType::from_str(&v.value.to_string())) {
768              Some(val) => {
769                match val {
770                  Ok(val) => Some(val),
771                  Err(msg) => throw_msg(msg, p1)?,
772                }
773              }
774              None => None,
775            }
776          }
777          "name" => acc.name = attr.value.clone().map(|v| v.value.to_string()),
778          "note" => acc.note = attr.value.clone().map(|v| v.value.to_string()),
779          _ => (),
780        }
781
782        acc.attributes.push(attr);
783      }
784      _ => throw_rules(&[Rule::attribute], p1)?,
785    }
786
787    Ok(acc)
788  })
789}
790
791fn parse_string_value(pair: Pair<Rule>) -> ParserResult<String> {
792  let mut out = String::new();
793
794  for p1 in pair.into_inner() {
795    match p1.as_rule() {
796      Rule::triple_quoted_string => {
797        for p2 in p1.into_inner() {
798          match p2.as_rule() {
799            Rule::triple_quoted_value => out = p2.as_str().to_string(),
800            _ => throw_rules(&[Rule::triple_quoted_value], p2)?,
801          }
802        }
803      }
804      Rule::single_quoted_string => {
805        for p2 in p1.into_inner() {
806          match p2.as_rule() {
807            Rule::single_quoted_value => out = p2.as_str().to_string(),
808            _ => throw_rules(&[Rule::single_quoted_value], p2)?,
809          }
810        }
811      }
812      _ => throw_rules(&[Rule::triple_quoted_string, Rule::single_quoted_string], p1)?,
813    }
814  }
815
816  Ok(out)
817}
818
819fn parse_value(pair: Pair<Rule>) -> ParserResult<Value> {
820  let p1 = pair
821    .into_inner()
822    .next()
823    .ok_or_else(|| unreachable!("something went wrong at value"))?;
824
825  match p1.as_rule() {
826    Rule::string_value => {
827      let value = parse_string_value(p1)?;
828
829      Ok(Value::String(value))
830    }
831    Rule::number_value => {
832      let p2 = p1
833        .into_inner()
834        .next()
835        .ok_or_else(|| unreachable!("something went wrong at value"))?;
836
837      match p2.as_rule() {
838        Rule::decimal => {
839          match p2.as_str().parse::<f64>() {
840            Ok(val) => Ok(Value::Decimal(val)),
841            Err(err) => throw_msg(err.to_string(), p2)?,
842          }
843        }
844        Rule::integer => {
845          match p2.as_str().parse::<i64>() {
846            Ok(val) => Ok(Value::Integer(val)),
847            Err(err) => throw_msg(err.to_string(), p2)?,
848          }
849        }
850        _ => throw_rules(&[Rule::decimal, Rule::integer], p2)?,
851      }
852    }
853    Rule::boolean_value => {
854      if let Ok(v) = Value::from_str(p1.as_str()) {
855        Ok(v)
856      } else {
857        throw_msg(format!("'{}' is incompatible with boolean value", p1.as_str()), p1)?
858      }
859    }
860    Rule::hex_value => Ok(Value::HexColor(p1.as_str().to_string())),
861    Rule::backquoted_quoted_string => Ok(Value::Expr(p1.into_inner().as_str().to_string())),
862    _ => {
863      throw_rules(
864        &[
865          Rule::string_value,
866          Rule::number_value,
867          Rule::boolean_value,
868          Rule::hex_value,
869          Rule::backquoted_quoted_string,
870        ],
871        p1,
872      )?
873    }
874  }
875}
876
877fn parse_decl_ident(pair: Pair<Rule>) -> ParserResult<(Option<Ident>, Ident)> {
878  let mut tmp_tokens = vec![];
879
880  for p1 in pair.into_inner() {
881    match p1.as_rule() {
882      Rule::ident => tmp_tokens.push(parse_ident(p1)?),
883      _ => throw_rules(&[Rule::ident], p1)?,
884    }
885  }
886
887  let (schema, name) = match tmp_tokens.len() {
888    1 => (None, tmp_tokens.remove(0)),
889    2 => {
890      let schema = Some(tmp_tokens.remove(0));
891
892      (schema, tmp_tokens.remove(0))
893    }
894    _ => unreachable!("unwell formatted decl_ident"),
895  };
896
897  Ok((schema, name))
898}
899
900fn parse_ident(pair: Pair<Rule>) -> ParserResult<Ident> {
901  let p1 = pair
902    .into_inner()
903    .next()
904    .ok_or_else(|| unreachable!("something went wrong at ident"))?;
905
906  let ident = match p1.as_rule() {
907    Rule::var => {
908      Ident {
909        span_range: s2r(p1.as_span()),
910        raw: p1.as_str().to_string(),
911        to_string: p1.as_str().to_string(),
912      }
913    }
914    Rule::double_quoted_string => {
915      Ident {
916        span_range: s2r(p1.as_span()),
917        raw: p1.as_str().to_string(),
918        to_string: p1.into_inner().as_str().to_string(),
919      }
920    }
921    _ => throw_rules(&[Rule::var, Rule::double_quoted_string], p1)?,
922  };
923
924  Ok(ident)
925}
926
927pub fn parse_attribute(pair: Pair<Rule>) -> ParserResult<Attribute> {
928  let mut init = Attribute {
929    span_range: s2r(pair.as_span()),
930    ..Default::default()
931  };
932
933  for p1 in pair.into_inner() {
934    match p1.as_rule() {
935      Rule::spaced_var => {
936        if init.key.raw.is_empty() {
937          init.key = Ident {
938            span_range: s2r(p1.as_span()),
939            raw: p1.as_str().to_string(),
940            to_string: p1.as_str().to_string(),
941          };
942        } else {
943          init.value = Some(Literal {
944            span_range: s2r(p1.as_span()),
945            raw: p1.as_str().to_string(),
946            value: Value::Enum(p1.as_str().to_string()),
947          })
948        }
949      }
950      Rule::value => {
951        init.value = Some(Literal {
952          span_range: s2r(p1.as_span()),
953          raw: p1.as_str().to_string(),
954          value: parse_value(p1)?,
955        })
956      }
957      Rule::double_quoted_string => {
958        init.value = Some(Literal {
959          span_range: s2r(p1.as_span()),
960          raw: p1.as_str().to_string(),
961          value: Value::String(p1.into_inner().as_str().to_string()),
962        })
963      }
964      _ => throw_rules(&[Rule::value, Rule::spaced_var, Rule::double_quoted_string], p1)?,
965    }
966  }
967
968  Ok(init)
969}
970
971pub fn parse_property(pair: Pair<Rule>) -> ParserResult<Property> {
972  let init = parse_attribute(pair.clone())?;
973
974  match init.value {
975    Some(value) => {
976      Ok(Property {
977        span_range: init.span_range,
978        key: init.key,
979        value,
980      })
981    }
982    None => throw_rules(&[Rule::property], pair),
983  }
984}