1pub use rustidy_macros::ParseError;
5
6use {
8 super::{AstPos, AstRange, Parse, Parser},
9 app_error::AppError,
10 core::{error::Error as StdError, fmt},
11};
12
13pub trait ParseError {
15 fn is_fatal(&self) -> bool;
17
18 fn pos(&self) -> Option<AstPos>;
20
21 fn to_app_error(&self, parser: &Parser) -> AppError;
23}
24
25impl ParseError for ! {
26 fn is_fatal(&self) -> bool {
27 *self
28 }
29
30 fn pos(&self) -> Option<AstPos> {
31 *self
32 }
33
34 fn to_app_error(&self, _parser: &Parser) -> AppError {
35 *self
36 }
37}
38
39impl<E: ParseError> ParseError for Box<E> {
40 fn is_fatal(&self) -> bool {
41 (**self).is_fatal()
42 }
43
44 fn pos(&self) -> Option<AstPos> {
45 (**self).pos()
46 }
47
48 fn to_app_error(&self, parser: &Parser) -> AppError {
49 (**self).to_app_error(parser)
50 }
51}
52
53impl ParseError for () {
54 fn is_fatal(&self) -> bool {
55 false
56 }
57
58 fn pos(&self) -> Option<AstPos> {
59 None
60 }
61
62 fn to_app_error(&self, _parser: &Parser) -> AppError {
63 AppError::from_multiple([])
64 }
65}
66
67
68pub struct ParserError<T: Parse> {
70 source: Box<T::Error>,
75 range: AstRange,
76}
77
78impl<T: Parse> ParserError<T> {
79 pub(super) fn new(source: T::Error, range: AstRange) -> Self {
80 Self { source: Box::new(source), range, }
81 }
82}
83
84impl<T: Parse<Error: fmt::Debug>> fmt::Debug for ParserError<T> {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f
87 .debug_struct("ParserError")
88 .field("source", &self.source)
89 .field("span", &self.range).finish()
90 }
91}
92
93impl<T: Parse<Error: StdError + 'static>> StdError for ParserError<T> {
94 fn source(&self) -> Option<&( dyn StdError + 'static )> {
95 match self::name_of::<T>().is_some() {
96 true => Some(&self.source),
97 false => self.source.source(),
98 }
99 }
100}
101
102impl<T: Parse<Error: fmt::Display>> fmt::Display for ParserError<T> {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self::name_of::<T>() {
105 Some(name) => write!(f, "Expected {name}"),
106 None => self.source.fmt(f),
107 }
108 }
109}
110
111impl<T: Parse> ParseError for ParserError<T> {
112 fn is_fatal(&self) -> bool {
113 self.source.is_fatal()
114 }
115
116 fn pos(&self) -> Option<AstPos> {
117 let pos = match self.source.pos() {
120 Some(pos) => AstPos::max(pos, self.range.end),
121 None => self.range.end,
122 };
123
124 Some(pos)
125 }
126
127 fn to_app_error(&self, parser: &Parser) -> AppError {
128 let err = self.source.to_app_error(parser).flatten();
129 match self::name_of::<T>() {
130 Some(name) => err.with_context(
131 || format!("Expected {name} at {}", parser.loc(self.range.start))
132 ),
133 None => err,
134 }
135 }
136}
137
138fn name_of<T: Parse>() -> Option<String> {
140 let name = T::name().map(|s| s.to_string());
141
142 #[cfg(feature = "parse-debug-name")]
143 let name = Some(
144 name
145 .unwrap_or_else(|| std::any::type_name::<T>().to_owned())
146 );
147
148 name
149}