1use crate::Token;
2use crate::tokenizer;
3
4#[derive(thiserror::Error, Debug)]
6pub enum ParseError {
7 #[error("parse error near token: {}", .0.location().start)]
9 ParsingNearToken(Token),
10
11 #[error("parse error at end of input")]
13 ParsingAtEndOfInput,
14
15 #[error("failed to tokenize input")]
17 Tokenizing {
18 inner: tokenizer::TokenizerError,
20 position: Option<tokenizer::SourcePosition>,
22 },
23}
24
25#[cfg(feature = "diagnostics")]
26#[allow(clippy::cast_sign_loss)]
27pub mod miette {
28 use super::ParseError;
29 use miette::SourceOffset;
30
31 impl ParseError {
32 pub fn to_pretty_error(self, input: impl Into<String>) -> PrettyError {
34 let input = input.into();
35 let location = match self {
36 Self::ParsingNearToken(ref token) => Some(SourceOffset::from_location(
37 &input,
38 token.location().start.line as usize,
39 token.location().start.column as usize,
40 )),
41 Self::Tokenizing { ref position, .. } => position.as_ref().map(|p| {
42 SourceOffset::from_location(&input, p.line as usize, p.column as usize)
43 }),
44 Self::ParsingAtEndOfInput => {
45 Some(SourceOffset::from_location(&input, usize::MAX, usize::MAX))
46 }
47 };
48
49 PrettyError {
50 cause: self,
51 input,
52 location,
53 }
54 }
55 }
56
57 #[derive(thiserror::Error, Debug, miette::Diagnostic)]
59 #[error("Cannot parse the input script")]
60 pub struct PrettyError {
61 cause: ParseError,
62 #[source_code]
63 input: String,
64 #[label("{cause}")]
65 location: Option<SourceOffset>,
66 }
67}
68
69#[derive(Debug, thiserror::Error)]
71#[error(transparent)]
72pub struct ParseErrorLocation {
73 #[from]
74 inner: peg::error::ParseError<peg::str::LineCol>,
75}
76
77#[derive(Debug, thiserror::Error)]
79pub enum WordParseError {
80 #[error("failed to parse arithmetic expression")]
82 ArithmeticExpression(ParseErrorLocation),
83
84 #[error("failed to parse pattern")]
86 Pattern(ParseErrorLocation),
87
88 #[error("failed to parse prompt string")]
90 Prompt(ParseErrorLocation),
91
92 #[error("failed to parse parameter '{0}'")]
94 Parameter(String, ParseErrorLocation),
95
96 #[error("failed to parse for brace expansion: '{0}'")]
98 BraceExpansion(String, ParseErrorLocation),
99
100 #[error("failed to parse word '{0}'")]
102 Word(String, ParseErrorLocation),
103}
104
105#[derive(Debug, thiserror::Error)]
107#[error(transparent)]
108pub struct TestCommandParseError(#[from] peg::error::ParseError<usize>);
109
110#[derive(Debug, thiserror::Error)]
112pub enum BindingParseError {
113 #[error("unknown error while parsing key-binding: '{0}'")]
115 Unknown(String),
116
117 #[error("missing key code in key-binding")]
119 MissingKeyCode,
120}
121
122pub(crate) fn convert_peg_parse_error(
123 err: &peg::error::ParseError<usize>,
124 tokens: &[Token],
125) -> ParseError {
126 let approx_token_index = err.location;
127
128 if approx_token_index < tokens.len() {
129 ParseError::ParsingNearToken(tokens[approx_token_index].clone())
130 } else {
131 ParseError::ParsingAtEndOfInput
132 }
133}