1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
mod parser;
pub use parser::parse;

pub mod ast;

#[cfg(test)]
mod test {
  use super::*;

  use crate::ast::{Stmt, Spanned};

  use ariadne::{
    Report,
    Label,
    Source as SourceCode,
    ReportKind, Color,
  };
  
  use chumsky::{error::SimpleReason, prelude::Simple};

  fn display_errs(src: &str, errs: &Vec<Simple<char>>) {
    let start = errs.iter()
      .map(|err| err.span())
      .fold(src.len(), |min, cur| if cur.start < min { cur.start } else { min });

    Report::build(ReportKind::Error, (), start)
      .with_labels(
        errs.iter()
          .map(|err| {
            Label::new(err.span())
            .with_message(match err.reason() {
              SimpleReason::Unexpected => err.to_string(),
              SimpleReason::Unclosed { span: _, delimiter } => format!("Unmatched delimited {}", delimiter),
              SimpleReason::Custom(msg) => msg.clone(),
            })
            .with_color(Color::Red)
          })
      )
      .finish()
      .eprint(SourceCode::from(src.clone()))
      .unwrap();
  }

  fn _parse(src: &str) -> Result<Vec<Spanned<Stmt>>, Vec<Simple<char>>> {
    let res = parse(src);

    match res {
      Ok(ast) => Ok(ast),
      Err(errs) => {
        display_errs(&src, &errs);
        Err(errs)
      },
    }
  }

  #[test]
  fn it_works() {
    let res = _parse("
      import * from @core/ipa
      
      series F = { i, e, ε, æ }

      class X encodes (Place Manner) {
        ℂ = velar trill,
        ℤ = labiodental lateral_fricative ,
      }

      lang OEng : Old English
      lang OEng < AmEng : American English
      lang OEng < RP : Received Pronunciation
      
      @ 1000, OEng
      
      - water /ˈwæ.ter/ {
        noun. liquid that forms the seas, lakes, rivers, and rain
        verb. pour or sprinkle water over a plant or area
      }
      
      @ 1940, AmEng
      
      $ [C+alveolar+stop] > [+flap] / V_V : Alveolar stops lenite to flaps intervocallically
    ");

    println!("{:#?}", res);

    assert!(res.is_ok())
  }
}