1use std::ops::Range;
2
3use thiserror::Error;
4
5#[derive(Debug, PartialEq, Error)]
6#[error("parse error at {start_pos}..{end_pos}: {kind}")]
7pub struct ParseError {
8 pub start_pos: usize,
9 pub end_pos: usize,
10 pub kind: ParseErrorKind,
11}
12
13impl ParseError {
14 pub fn span(&self) -> Range<usize> {
15 self.start_pos..self.end_pos
16 }
17}
18
19#[derive(Debug, PartialEq, Error)]
20pub enum ParseErrorKind {
21 #[error("invalid token")]
22 Lex,
23 #[error("unexpected token, expecting: {0}")]
24 UnexpectedToken(String),
25 #[error("unexpected EOF, expecting: {0}")]
26 UnexpectedEof(String),
27 #[error("extra tokens")]
28 ExtraToken,
29 #[error("too many dereferences")]
30 TooManyDeref,
31
32 #[error("invalid redirection port")]
33 InvalidRedirectPort,
34
35 #[error("invalid '{0}' at this location")]
36 Validation(&'static str),
37}
38
39impl ParseError {
40 pub fn new(start_pos: usize, end_pos: usize, kind: ParseErrorKind) -> Self {
41 Self {
42 start_pos,
43 end_pos,
44 kind,
45 }
46 }
47}
48
49impl<T> From<lalrpop_util::ParseError<usize, T, ParseError>> for ParseError {
50 fn from(err: lalrpop_util::ParseError<usize, T, ParseError>) -> Self {
51 use lalrpop_util::ParseError as E;
52
53 let (start_pos, end_pos, kind) = match err {
54 E::UnrecognizedEof { location, expected } => (
55 location,
56 location,
57 ParseErrorKind::UnexpectedEof(expected.join(", ")),
58 ),
59 E::UnrecognizedToken { token, expected } => (
60 token.0,
61 token.2,
62 ParseErrorKind::UnexpectedToken(expected.join(", ")),
63 ),
64 E::ExtraToken { token } => (token.0, token.2, ParseErrorKind::ExtraToken),
65 E::User { error } => return error,
66 E::InvalidToken { .. } => unreachable!(),
67 };
68
69 Self::new(start_pos, end_pos, kind)
70 }
71}