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