1mod parser;
2pub use parser::parse;
3
4pub mod ast;
5
6#[cfg(test)]
7mod test {
8 use super::*;
9
10 use crate::ast::{Stmt, Spanned};
11
12 use ariadne::{
13 Report,
14 Label,
15 Source as SourceCode,
16 ReportKind, Color,
17 };
18
19 use chumsky::{error::SimpleReason, prelude::Simple};
20
21 fn display_errs(src: &str, errs: &Vec<Simple<char>>) {
22 let start = errs.iter()
23 .map(|err| err.span())
24 .fold(src.len(), |min, cur| if cur.start < min { cur.start } else { min });
25
26 Report::build(ReportKind::Error, (), start)
27 .with_labels(
28 errs.iter()
29 .map(|err| {
30 Label::new(err.span())
31 .with_message(match err.reason() {
32 SimpleReason::Unexpected => err.to_string(),
33 SimpleReason::Unclosed { span: _, delimiter } => format!("Unmatched delimited {}", delimiter),
34 SimpleReason::Custom(msg) => msg.clone(),
35 })
36 .with_color(Color::Red)
37 })
38 )
39 .finish()
40 .eprint(SourceCode::from(src.clone()))
41 .unwrap();
42 }
43
44 fn _parse(src: &str) -> Result<Vec<Spanned<Stmt>>, Vec<Simple<char>>> {
45 let res = parse(src);
46
47 match res {
48 Ok(ast) => Ok(ast),
49 Err(errs) => {
50 display_errs(&src, &errs);
51 Err(errs)
52 },
53 }
54 }
55
56 #[test]
57 fn it_works() {
58 let res = _parse("
59 import * from @core/ipa
60
61 series F = { i, e, ε, æ }
62
63 class X encodes (Place Manner) {
64 ℂ = velar trill,
65 ℤ = labiodental lateral_fricative ,
66 }
67
68 lang OEng : Old English
69 lang OEng < AmEng : American English
70 lang OEng < RP : Received Pronunciation
71
72 @ 1000, OEng
73
74 - water /ˈwæ.ter/ {
75 noun. liquid that forms the seas, lakes, rivers, and rain
76 verb. pour or sprinkle water over a plant or area
77 }
78
79 @ 1940, AmEng
80
81 $ [C+alveolar+stop] > [+flap] / V_V : Alveolar stops lenite to flaps intervocallically
82 ");
83
84 println!("{:#?}", res);
85
86 assert!(res.is_ok())
87 }
88}