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}