microcad_syntax/parser/
error.rs1use std::error::Error;
5use std::fmt::{Display, Formatter};
6use crate::Span;
7use crate::tokens::Token;
8use chumsky::error::{Rich, RichReason};
9use miette::{Diagnostic, LabeledSpan};
10use std::iter::once;
11
12#[derive(Debug)]
14pub struct ParseError {
15 pub span: Span,
17 error: Rich<'static, Token<'static>, Span>,
18}
19
20impl ParseError {
21 pub(crate) fn new<'tokens>(error: Rich<'tokens, Token<'tokens>, Span>) -> Self {
22 Self {
23 span: error.span().clone(),
24 error: error.map_token(Token::into_owned).into_owned(),
25 }
26 }
27}
28
29impl Display for ParseError {
30 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31 match self.error.reason() {
32 RichReason::Custom(error) => write!(f, "{error}"),
33 RichReason::ExpectedFound {
34 expected, ..
35 } => {
36 write!(f, "Expected ")?;
37 let mut expected = expected.iter();
38 if let Some(pattern) = expected.next() {
39 write!(f, "{pattern}")?;
40 }
41 let last = expected.next_back();
42 for pattern in expected {
43 write!(f, ", {pattern}")?;
44 };
45 if let Some(pattern) = last {
46 write!(f, " or {pattern}")?;
47 }
48 Ok(())
49 },
50 }
51 }
52}
53
54impl Error for ParseError {
55
56}
57
58impl Diagnostic for ParseError {
59 fn labels(&self) -> Option<Box<dyn Iterator<Item=LabeledSpan> + '_>> {
60 let msg = match self.error.reason() {
61 RichReason::Custom(error) => error.clone(),
62 RichReason::ExpectedFound {
63 found: Some(found), ..
64 } if found.is_error() => found.kind().into(),
65 RichReason::ExpectedFound {
66 found: Some(found), ..
67 } => format!("unexpected {}", found.kind()),
68 RichReason::ExpectedFound { found: None, .. } => "unexpected token".into(),
69 };
70 Some(Box::new(once(LabeledSpan::new(
71 Some(msg),
72 self.span.start,
73 self.span.len(),
74 ))))
75 }
76}