yew_router_min_route_parser/
error.rs1use nom::error::ErrorKind;
2use std::fmt;
3
4#[derive(Clone, PartialEq)]
6pub struct PrettyParseError<'a> {
7 pub error: ParseError,
9 pub input: &'a str,
11 pub remaining: &'a str,
13}
14
15fn offset(input: &str, substring: &str) -> usize {
17 input.len() - substring.len()
18}
19
20impl<'a> fmt::Debug for PrettyParseError<'a> {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 f.write_str("Could not parse route.")?;
23 f.write_str("\n")?;
24
25 let route_str: &str = "Route: ";
26 f.write_str(route_str)?;
27 f.write_str(self.input)?;
28 f.write_str("\n")?;
29
30 let offset = offset(self.input, self.remaining);
31 let offset = offset + self.error.offset;
32 let pad = (0..offset + route_str.len())
33 .map(|_| '-')
34 .collect::<String>();
35 f.write_str(&format!("{}^", pad))?;
36 f.write_str("\n")?;
37
38 if !self.error.expected.is_empty() {
39 f.write_str("Expected: ")?;
40 self.error.expected[..self.error.expected.len() - 1]
41 .iter()
42 .map(|expected| {
43 <ExpectedToken as fmt::Display>::fmt(expected, f)
44 .and_then(|_| f.write_str(", "))
45 })
46 .collect::<Result<(), fmt::Error>>()?;
47 self.error
48 .expected
49 .last()
50 .map(|expected| <ExpectedToken as fmt::Display>::fmt(expected, f))
51 .transpose()?;
52 f.write_str("\n")?;
53 }
54
55 if let Some(reason) = self.error.reason {
56 f.write_str("Reason: ")?;
57 <ParserErrorReason as fmt::Display>::fmt(&reason, f)?;
58 }
59
60 Ok(())
61 }
62}
63
64#[derive(Debug, Clone, PartialEq)]
66pub struct ParseError {
67 pub reason: Option<ParserErrorReason>,
69 pub expected: Vec<ExpectedToken>,
71 pub offset: usize,
74}
75
76impl ParseError {
77 pub(crate) fn expected(expected: ExpectedToken) -> Self {
78 ParseError {
79 reason: None,
80 expected: vec![expected],
81 offset: 0,
82 }
83 }
84}
85
86impl nom::error::ParseError<&str> for ParseError {
87 fn from_error_kind(_input: &str, _kind: ErrorKind) -> Self {
88 ParseError {
89 reason: None,
90 expected: vec![],
91 offset: 0,
92 }
93 }
94
95 fn append(_input: &str, _kind: ErrorKind, other: Self) -> Self {
96 other
97 }
98
99 fn or(mut self, other: Self) -> Self {
100 self.expected.extend(other.expected);
102
103 ParseError {
104 reason: other.reason.or(self.reason), expected: self.expected,
106 offset: other.offset, }
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq)]
112pub enum ExpectedToken {
113 Separator,
115 Literal,
117 QueryBegin,
119 QuerySeparator,
121 FragmentBegin,
123 End,
125 Ident,
127 OpenBracket,
129 CloseBracket,
131 Equals,
133 Star,
135 Colon,
137}
138
139impl fmt::Display for ExpectedToken {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 ExpectedToken::Separator => f.write_str("/"),
143 ExpectedToken::Literal => f.write_str("<literal>"),
144 ExpectedToken::QueryBegin => f.write_str("?"),
145 ExpectedToken::QuerySeparator => f.write_str("&"),
146 ExpectedToken::FragmentBegin => f.write_str("#"),
147 ExpectedToken::End => f.write_str("!"),
148 ExpectedToken::Ident => f.write_str("<ident>"),
149 ExpectedToken::OpenBracket => f.write_str("{"),
150 ExpectedToken::CloseBracket => f.write_str("}"),
151 ExpectedToken::Equals => f.write_str("="),
152 ExpectedToken::Star => f.write_str("*"),
153 ExpectedToken::Colon => f.write_str(":"),
154 }
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq)]
160pub enum ParserErrorReason {
161 TokensAfterEndToken,
163 DoubleSlash,
165 EndAfterCapture,
167 AndBeforeQuestion,
169 AdjacentCaptures,
171 MultipleQuestions,
173 BadRustIdent(char),
175 BadLiteral,
177 InvalidState,
179 CapturesInUnit,
181 NotAllowedStateTransition,
184 Expected(ExpectedToken),
186}
187
188impl fmt::Display for ParserErrorReason {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 match self {
191 ParserErrorReason::TokensAfterEndToken => {
192 f.write_str("Characters appeared after the end token (!).")?;
193 }
194 ParserErrorReason::DoubleSlash => {
195 f.write_str("Two slashes are not allowed to be next to each other (//).")?;
196 }
197 ParserErrorReason::AndBeforeQuestion => {
198 f.write_str("The first query must be indicated with a '?', not a '&'.")?;
199 }
200 ParserErrorReason::AdjacentCaptures => {
201 f.write_str("Capture groups can't be next to each other. There must be some character in between the '}' and '{' characters.")?;
202 }
203 ParserErrorReason::InvalidState => {
204 f.write_str("Library Error: The parser was able to enter into an invalid state.")?;
205 }
206 ParserErrorReason::NotAllowedStateTransition => {
207 f.write_str("Library Error: A state transition was attempted that would put the parser in an invalid state")?;
208 }
209 ParserErrorReason::MultipleQuestions => {
210 f.write_str("There can only be one question mark in the query section. `&` should be used to separate other queries.")?;
211 }
212 ParserErrorReason::BadRustIdent(c) => {
213 f.write_str(&format!(
214 "The character: '{}' could not be used as a Rust identifier.",
215 c
216 ))?;
217 }
218 ParserErrorReason::EndAfterCapture => {
219 f.write_str("The end token (!) can't appear after a capture ({}).")?;
220 }
221 ParserErrorReason::Expected(expected) => {
222 f.write_str(&format!("Expected: {}", expected))?;
223 }
224 ParserErrorReason::BadLiteral => {
225 f.write_str("Malformed literal.")?;
226 }
227 ParserErrorReason::CapturesInUnit => {
228 f.write_str("Cannot have a capture section for a unit struct or variant.")?;
229 }
230 }
231 Ok(())
232 }
233}
234
235pub(crate) fn get_reason(err: &mut nom::Err<ParseError>) -> &mut Option<ParserErrorReason> {
236 match err {
237 nom::Err::Error(err) | nom::Err::Failure(err) => &mut err.reason,
238 nom::Err::Incomplete(_) => panic!("Incomplete not possible"),
239 }
240}