kodept_parse/
error.rs

1use std::borrow::Cow;
2
3use derive_more::Constructor;
4
5use kodept_core::code_point::CodePoint;
6
7use crate::lexer::Token;
8use crate::token_stream::TokenStream;
9
10#[derive(Debug, Constructor)]
11pub struct ErrorLocation {
12    pub in_stream: usize,
13    pub in_code: CodePoint,
14}
15
16#[derive(Debug, Constructor)]
17pub struct ParseError<A> {
18    pub expected: Vec<Cow<'static, str>>,
19    pub actual: A,
20    pub location: ErrorLocation,
21}
22
23#[derive(Debug, Constructor)]
24pub struct ParseErrors<A> {
25    errors: Vec<ParseError<A>>,
26}
27
28pub trait Original<Actual> {
29    fn point_pos(&self, point: impl Into<CodePoint>) -> usize;
30    fn actual(&self, point: impl Into<CodePoint>) -> Actual;
31}
32
33impl<A> IntoIterator for ParseErrors<A> {
34    type Item = ParseError<A>;
35    type IntoIter = std::vec::IntoIter<ParseError<A>>;
36
37    fn into_iter(self) -> Self::IntoIter {
38        self.errors.into_iter()
39    }
40}
41
42impl<'t> Original<Token<'t>> for TokenStream<'t> {
43    fn point_pos(&self, point: impl Into<CodePoint>) -> usize {
44        let stream = *self;
45        let point1 = point.into();
46        stream
47            .slice
48            .iter()
49            .position(|it| it.span.point == point1)
50            .unwrap()
51    }
52
53    fn actual(&self, point: impl Into<CodePoint>) -> Token<'t> {
54        let pos = self.point_pos(point);
55        self.slice[pos].token
56    }
57}
58
59impl<'a, S: From<&'a str>> Original<S> for &'a str {
60    fn point_pos(&self, point: impl Into<CodePoint>) -> usize {
61        let point = point.into();
62        point.offset as usize
63    }
64
65    fn actual(&self, point: impl Into<CodePoint>) -> S {
66        let point = point.into();
67        S::from(&self[point.as_range()])
68    }
69}
70
71impl<A> ParseError<A> {
72    pub fn map<B>(self, f: impl FnOnce(A) -> B) -> ParseError<B> {
73        ParseError {
74            expected: self.expected,
75            actual: f(self.actual),
76            location: self.location,
77        }
78    }
79}
80
81impl<A> ParseErrors<A> {
82    pub fn map<B>(self, mut f: impl FnMut(A) -> B) -> ParseErrors<B> {
83        ParseErrors::new(self.into_iter().map(move |it| it.map(&mut f)).collect())
84    }
85}