1use crate::{Posn, Span};
3use thiserror::Error;
4
5pub type MarkupResult<T> = std::result::Result<T, MarkupError>;
12
13pub type HmlResult<T, P> = std::result::Result<T, HmlError<P>>;
17
18#[derive(Debug, Error)]
25pub enum MarkupError {
26 #[error("empty name")]
29 EmptyName {},
30 #[error("unmapped_prefix {prefix}")]
32 UnmappedPrefix {
33 prefix: String,
35 },
36 #[error("bad name {name}")]
38 BadName {
39 name: String,
41 },
42}
43
44impl MarkupError {
46 pub fn empty_name() -> Self {
50 Self::EmptyName {}
51 }
52
53 pub fn unmapped_prefix(prefix: &str) -> Self {
58 Self::UnmappedPrefix {
59 prefix: prefix.to_string(),
60 }
61 }
62
63 pub fn bad_name(name: &str) -> Self {
66 Self::BadName {
67 name: name.to_string(),
68 }
69 }
70}
71
72#[derive(Debug, Error)]
78pub enum HmlError<P>
79where
80 P: Posn,
81{
82 #[error("io error {source}")]
84 IoError {
85 span: Span<P>,
87 source: std::io::Error,
89 },
90 #[error("markup error {source}")]
92 MarkupError {
93 span: Span<P>,
95 source: MarkupError,
97 },
98 #[error("Expected a tag name after hashes")]
100 ExpectedTagName {
101 span: Span<P>,
103 },
104 #[error("Expected whitespace after tag")]
106 ExpectedWhitespaceAfterTag {
107 span: Span<P>,
109 },
110 #[error("Unexpected character '{ch}'")]
112 UnexpectedCharacter {
113 span: Span<P>,
115 ch: char,
117 },
118 #[error("Expected a tag indent of at most {depth}")]
120 UnexpectedTagIndent {
121 span: Span<P>,
123 depth: usize,
125 },
126 #[error("Attempt to parse beyond end of tokens, probably a bug")]
128 BeyondEndOfTokens,
129 #[error("Found attribute when not expected {attr}")]
131 UnexpectedAttribute {
132 span: Span<P>,
134 attr: String,
136 },
137 #[error("Unexpected newline in quoted string")]
139 UnexpectedNewlineInQuotedString {
140 span: Span<P>,
142 },
143 #[error("Expected equals, but found '{ch}'")]
145 ExpectedEquals {
146 span: Span<P>,
148 ch: char,
150 },
151 #[error("Unexpected EOF")]
153 UnexpectedEOF {
154 span: Span<P>,
156 },
157}
158
159impl<P> HmlError<P>
161where
162 P: Posn,
163{
164 pub fn unexpected_eof<T>(start: &P, end: &P) -> HmlResult<T, P> {
167 let span = Span::new_at(start).end_at(end);
168 Err(Self::UnexpectedEOF { span })
169 }
170
171 pub fn unexpected_character<T>(start: &P, end: &P, ch: char) -> HmlResult<T, P> {
174 let span = Span::new_at(start).end_at(end);
175 Err(Self::UnexpectedCharacter { span, ch })
176 }
177
178 pub fn unexpected_newline_in_string<T>(start: &P, end: &P) -> HmlResult<T, P> {
181 let span = Span::new_at(start).end_at(end);
182 Err(Self::UnexpectedNewlineInQuotedString { span })
183 }
184
185 pub fn expected_equals<T>(start: &P, end: &P, ch: char) -> HmlResult<T, P> {
188 let span = Span::new_at(start).end_at(end);
189 Err(Self::ExpectedEquals { span, ch })
190 }
191
192 pub fn no_more_events<T>() -> HmlResult<T, P> {
195 Err(Self::BeyondEndOfTokens)
196 }
197
198 pub fn unexpected_tag_indent<T>(span: Span<P>, depth: usize) -> HmlResult<T, P> {
201 Err(Self::UnexpectedTagIndent { span, depth })
202 }
203
204 pub fn unexpected_attribute<T>(span: Span<P>, prefx: &str, name: &str) -> HmlResult<T, P> {
207 let attr = format!("{}:{}", prefx, name);
208 Err(Self::UnexpectedAttribute { span, attr })
209 }
210
211 pub fn io_error(span: Span<P>, source: std::io::Error) -> Self {
214 Self::IoError { span, source }
215 }
216
217 pub fn of_io_result<T>(
220 span: Span<P>,
221 r: std::result::Result<T, std::io::Error>,
222 ) -> HmlResult<T, P> {
223 match r {
224 Ok(t) => Ok(t),
225 Err(e) => Err(Self::io_error(span, e)),
226 }
227 }
228}
229
230impl<P> HmlError<P>
232where
233 P: Posn,
234{
235 pub fn span(&self) -> Option<&Span<P>> {
238 match self {
239 Self::IoError { span, .. } => Some(span),
240 Self::UnexpectedCharacter { span, .. } => Some(span),
241 Self::UnexpectedTagIndent { span, .. } => Some(span),
242 Self::UnexpectedAttribute { span, .. } => Some(span),
243 Self::UnexpectedEOF { span, .. } => Some(span),
244 Self::UnexpectedNewlineInQuotedString { span, .. } => Some(span),
245 Self::ExpectedEquals { span, .. } => Some(span),
246 Self::BeyondEndOfTokens => None,
247 Self::MarkupError { span, .. } => Some(span),
248 Self::ExpectedTagName { span, .. } => Some(span),
249 Self::ExpectedWhitespaceAfterTag { span, .. } => Some(span),
250 }
251 }
252
253 #[inline(always)]
258 pub fn map_markup_error<T>(result: MarkupResult<T>, span: &Span<P>) -> HmlResult<T, P> {
259 match result {
260 Err(source) => Err(Self::MarkupError {
261 source,
262 span: *span,
263 }),
264 Ok(t) => Ok(t),
265 }
266 }
267}
268
269impl<P> lexer_rs::LexerError<P> for HmlError<P>
271where
272 P: Posn,
273{
274 fn failed_to_parse(posn: P, ch: char) -> Self {
279 let span = Span::new_at(&posn);
280 Self::UnexpectedCharacter { span, ch }
281 }
282}