scarf_parser/parser/
mod.rs

1// =======================================================================
2// mod.rs
3// =======================================================================
4// The top-level interface for the parser
5
6pub mod declarations;
7pub mod errors;
8pub mod expressions;
9pub mod general;
10pub mod source_text;
11pub mod udp_declaration_and_instantiation;
12pub mod utils;
13use crate::*;
14use ariadne::Report;
15use ariadne::{Color, Label, ReportKind};
16use chumsky::error::{RichPattern, RichReason};
17use chumsky::input::ValueInput;
18use chumsky::prelude::*;
19pub use scarf_syntax::SourceText;
20pub use declarations::*;
21pub use errors::*;
22pub use expressions::*;
23pub use general::*;
24pub use source_text::*;
25pub use udp_declaration_and_instantiation::*;
26pub use utils::*;
27
28pub type ParserSpan = SimpleSpan;
29
30pub fn parse<'a, I>(src: I) -> ParseResult<SourceText<'a>, Rich<'a, Token<'a>>>
31where
32    I: ValueInput<'a, Token = Token<'a>, Span = ParserSpan>,
33{
34    source_text_parser().parse(src)
35}
36
37fn format_pattern<'a>(pattern: &RichPattern<'a, Token<'a>>) -> String {
38    match pattern {
39        RichPattern::Token(tok) => tok.to_string(),
40        RichPattern::Label(l) => l.to_string(),
41        RichPattern::Identifier(i) => i.to_string(),
42        RichPattern::Any => "any".to_owned(),
43        RichPattern::SomethingElse => "something else".to_owned(),
44        RichPattern::EndOfInput => "end of input".to_owned(),
45    }
46}
47
48fn format_reason<'a>(reason: &RichReason<'a, Token<'a>>) -> String {
49    match reason {
50        RichReason::ExpectedFound { expected, found } => {
51            let found_str = match found.as_deref() {
52                Some(tok) => tok.to_string(),
53                None => "end of input".to_owned(),
54            };
55            let expected_str = match &expected[..] {
56                [] => "something else".to_owned(),
57                [expected] => format_pattern(expected),
58                _ => {
59                    let mut temp_expected_str = String::new();
60                    for expected in &expected[..expected.len() - 1] {
61                        temp_expected_str.push_str(format_pattern(expected).as_str());
62                        temp_expected_str.push_str(", ");
63                    }
64                    temp_expected_str.push_str("or ");
65                    temp_expected_str.push_str(format_pattern(expected.last().unwrap()).as_str());
66                    temp_expected_str
67                }
68            };
69            format!("found {}, expected {}", found_str, expected_str)
70        }
71        RichReason::Custom(str) => str.clone(),
72    }
73}
74
75fn format_reason_short<'a>(reason: &RichReason<'a, Token<'a>>) -> String {
76    match reason {
77        RichReason::ExpectedFound { expected: _, found } => match found.as_deref() {
78            Some(tok) => format!("Didn't expect {}", tok.to_string()),
79            None => "Didn't expect end of input".to_owned(),
80        },
81        RichReason::Custom(str) => str.clone(),
82    }
83}
84
85pub fn report_parse_errors<'a, 'b>(
86    result: ParseResult<SourceText, Rich<'a, Token<'a>, ParserSpan>>,
87    file_path: &'b str,
88) -> Vec<Report<'a, (&'b str, std::ops::Range<usize>)>> {
89    let mut reports: Vec<Report<'a, (&'b str, std::ops::Range<usize>)>> = Vec::new();
90    result.into_errors().into_iter().for_each(|e| {
91        let report = Report::build(ReportKind::Error, (file_path, e.span().into_range()))
92            .with_config(ariadne::Config::new().with_index_type(ariadne::IndexType::Byte))
93            .with_message(format_reason(e.reason()))
94            .with_label(
95                Label::new((file_path, e.span().into_range()))
96                    .with_message(format_reason_short(e.reason()))
97                    .with_color(Color::Red),
98            )
99            .finish();
100        reports.push(report);
101    });
102    reports
103}