1use crate::Span;
2
3pub trait ErrorSink {
4 fn report_error(&mut self, error: ParseError);
5}
6
7impl<F> ErrorSink for F
8where
9 F: FnMut(ParseError),
10{
11 fn report_error(&mut self, error: ParseError) {
12 (self)(error);
13 }
14}
15
16impl ErrorSink for () {
17 fn report_error(&mut self, _error: ParseError) {}
18}
19
20impl ErrorSink for Option<ParseError> {
21 fn report_error(&mut self, error: ParseError) {
22 self.get_or_insert(error);
23 }
24}
25
26#[cfg(feature = "alloc")]
27#[allow(unused_qualifications)]
28impl ErrorSink for alloc::vec::Vec<ParseError> {
29 fn report_error(&mut self, error: ParseError) {
30 self.push(error);
31 }
32}
33
34#[derive(Clone, PartialEq, Eq, Debug)]
35#[non_exhaustive]
36pub struct ParseError {
37 context: Option<Span>,
38 description: ErrorStr,
39 expected: Option<&'static [Expected]>,
40 unexpected: Option<Span>,
41}
42
43impl ParseError {
44 pub fn new(description: impl Into<ErrorStr>) -> Self {
45 Self {
46 context: None,
47 description: description.into(),
48 expected: None,
49 unexpected: None,
50 }
51 }
52
53 pub fn with_context(mut self, context: Span) -> Self {
54 self.context = Some(context);
55 self
56 }
57
58 pub fn with_expected(mut self, expected: &'static [Expected]) -> Self {
59 self.expected = Some(expected);
60 self
61 }
62
63 pub fn with_unexpected(mut self, unexpected: Span) -> Self {
64 self.unexpected = Some(unexpected);
65 self
66 }
67
68 pub fn context(&self) -> Option<Span> {
69 self.context
70 }
71 pub fn description(&self) -> &str {
72 &self.description
73 }
74 pub fn expected(&self) -> Option<&'static [Expected]> {
75 self.expected
76 }
77 pub fn unexpected(&self) -> Option<Span> {
78 self.unexpected
79 }
80
81 pub(crate) fn rebase_spans(mut self, offset: usize) -> Self {
82 if let Some(context) = self.context.as_mut() {
83 *context += offset;
84 }
85 if let Some(unexpected) = self.unexpected.as_mut() {
86 *unexpected += offset;
87 }
88 self
89 }
90}
91
92#[cfg(feature = "alloc")]
93type ErrorStr = alloc::borrow::Cow<'static, str>;
94#[cfg(not(feature = "alloc"))]
95type ErrorStr = &'static str;
96
97#[derive(Copy, Clone, PartialEq, Eq, Debug)]
98#[non_exhaustive]
99pub enum Expected {
100 Literal(&'static str),
101 Description(&'static str),
102}