1use crate::tokenizer;
2
3#[derive(thiserror::Error, Debug)]
5pub enum ParseError {
6 #[error("syntax error at line {} col {}", .0.line, .0.column)]
8 ParsingNear(crate::SourcePosition),
9
10 #[error("syntax error at end of input")]
12 ParsingAtEndOfInput,
13
14 #[error("{} (detected near {})", .inner, .position.as_ref().map_or_else(|| String::from("<unknown position>"), |p| std::format!("line {} col {}", p.line, p.column)))]
16 Tokenizing {
17 inner: tokenizer::TokenizerError,
19 position: Option<crate::SourcePosition>,
21 },
22}
23
24#[cfg(feature = "diagnostics")]
25#[allow(clippy::cast_sign_loss)]
26#[allow(unused)] pub mod miette {
28 use miette::SourceOffset;
29
30 use super::ParseError;
31
32 impl ParseError {
33 pub fn to_pretty_error(self, input: impl Into<String>) -> PrettyError {
35 let input = input.into();
36 let location = match self {
37 Self::ParsingNear(ref pos) => {
38 Some(SourceOffset::from_location(&input, pos.line, pos.column))
39 }
40 Self::Tokenizing { ref position, .. } => position
41 .as_ref()
42 .map(|p| SourceOffset::from_location(&input, p.line, p.column)),
43 Self::ParsingAtEndOfInput => {
44 Some(SourceOffset::from_location(&input, usize::MAX, usize::MAX))
45 }
46 };
47
48 PrettyError {
49 cause: self,
50 input,
51 location,
52 }
53 }
54 }
55
56 #[derive(thiserror::Error, Debug, miette::Diagnostic)]
58 #[error("Cannot parse the input script")]
59 pub struct PrettyError {
60 cause: ParseError,
61 #[source_code]
62 input: String,
63 #[label("{cause}")]
64 location: Option<SourceOffset>,
65 }
66}
67
68#[derive(Debug, thiserror::Error)]
70#[error(transparent)]
71pub struct ParseErrorLocation {
72 #[from]
73 inner: peg::error::ParseError<peg::str::LineCol>,
74}
75
76#[derive(Debug, thiserror::Error)]
78pub enum WordParseError {
79 #[error("failed to parse arithmetic expression")]
81 ArithmeticExpression(ParseErrorLocation),
82
83 #[error("failed to parse pattern")]
85 Pattern(ParseErrorLocation),
86
87 #[error("failed to parse prompt string")]
89 Prompt(ParseErrorLocation),
90
91 #[error("failed to parse parameter '{0}'")]
93 Parameter(String, ParseErrorLocation),
94
95 #[error("failed to parse for brace expansion: '{0}'")]
97 BraceExpansion(String, ParseErrorLocation),
98
99 #[error("failed to parse word '{0}'")]
101 Word(String, ParseErrorLocation),
102}
103
104#[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: &[crate::Token],
125) -> ParseError {
126 let approx_token_index = err.location;
127
128 if approx_token_index < tokens.len() {
129 let token = &tokens[approx_token_index];
130 ParseError::ParsingNear((*token.location().start).clone())
131 } else {
132 ParseError::ParsingAtEndOfInput
133 }
134}