yew_router_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 .try_for_each(|expected| {
43 <ExpectedToken as fmt::Display>::fmt(expected, f)
44 .and_then(|_| f.write_str(", "))
45 })?;
46 self.error
47 .expected
48 .last()
49 .map(|expected| <ExpectedToken as fmt::Display>::fmt(expected, f))
50 .transpose()?;
51 f.write_str("\n")?;
52 }
53
54 if let Some(reason) = self.error.reason {
55 f.write_str("Reason: ")?;
56 <ParserErrorReason as fmt::Display>::fmt(&reason, f)?;
57 }
58
59 Ok(())
60 }
61}
62
63#[derive(Debug, Clone, PartialEq)]
65pub struct ParseError {
66 pub reason: Option<ParserErrorReason>,
68 pub expected: Vec<ExpectedToken>,
70 pub offset: usize,
73}
74
75impl ParseError {
76 pub(crate) fn expected(expected: ExpectedToken) -> Self {
77 ParseError {
78 reason: None,
79 expected: vec![expected],
80 offset: 0,
81 }
82 }
83}
84
85impl nom::error::ParseError<&str> for ParseError {
86 fn from_error_kind(_input: &str, _kind: ErrorKind) -> Self {
87 ParseError {
88 reason: None,
89 expected: vec![],
90 offset: 0,
91 }
92 }
93
94 fn append(_input: &str, _kind: ErrorKind, other: Self) -> Self {
95 other
96 }
97
98 fn or(mut self, other: Self) -> Self {
99 self.expected.extend(other.expected);
101
102 ParseError {
103 reason: other.reason.or(self.reason), expected: self.expected,
105 offset: other.offset, }
107 }
108}
109
110#[derive(Debug, Clone, Copy, PartialEq)]
111pub enum ExpectedToken {
112 Separator,
114 Literal,
116 QueryBegin,
118 QuerySeparator,
120 FragmentBegin,
122 End,
124 Ident,
126 OpenBracket,
128 CloseBracket,
130 Equals,
132 Star,
134 Colon,
136}
137
138impl fmt::Display for ExpectedToken {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 match self {
141 ExpectedToken::Separator => f.write_str("/"),
142 ExpectedToken::Literal => f.write_str("<literal>"),
143 ExpectedToken::QueryBegin => f.write_str("?"),
144 ExpectedToken::QuerySeparator => f.write_str("&"),
145 ExpectedToken::FragmentBegin => f.write_str("#"),
146 ExpectedToken::End => f.write_str("!"),
147 ExpectedToken::Ident => f.write_str("<ident>"),
148 ExpectedToken::OpenBracket => f.write_str("{"),
149 ExpectedToken::CloseBracket => f.write_str("}"),
150 ExpectedToken::Equals => f.write_str("="),
151 ExpectedToken::Star => f.write_str("*"),
152 ExpectedToken::Colon => f.write_str(":"),
153 }
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq)]
159pub enum ParserErrorReason {
160 TokensAfterEndToken,
162 DoubleSlash,
164 EndAfterCapture,
166 AndBeforeQuestion,
168 AdjacentCaptures,
170 MultipleQuestions,
172 BadRustIdent(char),
174 BadLiteral,
176 InvalidState,
178 CapturesInUnit,
180 NotAllowedStateTransition,
183 Expected(ExpectedToken),
185}
186
187impl fmt::Display for ParserErrorReason {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 match self {
190 ParserErrorReason::TokensAfterEndToken => {
191 f.write_str("Characters appeared after the end token (!).")?;
192 }
193 ParserErrorReason::DoubleSlash => {
194 f.write_str("Two slashes are not allowed to be next to each other (//).")?;
195 }
196 ParserErrorReason::AndBeforeQuestion => {
197 f.write_str("The first query must be indicated with a '?', not a '&'.")?;
198 }
199 ParserErrorReason::AdjacentCaptures => {
200 f.write_str("Capture groups can't be next to each other. There must be some character in between the '}' and '{' characters.")?;
201 }
202 ParserErrorReason::InvalidState => {
203 f.write_str("Library Error: The parser was able to enter into an invalid state.")?;
204 }
205 ParserErrorReason::NotAllowedStateTransition => {
206 f.write_str("Library Error: A state transition was attempted that would put the parser in an invalid state")?;
207 }
208 ParserErrorReason::MultipleQuestions => {
209 f.write_str("There can only be one question mark in the query section. `&` should be used to separate other queries.")?;
210 }
211 ParserErrorReason::BadRustIdent(c) => {
212 f.write_str(&format!(
213 "The character: '{}' could not be used as a Rust identifier.",
214 c
215 ))?;
216 }
217 ParserErrorReason::EndAfterCapture => {
218 f.write_str("The end token (!) can't appear after a capture ({}).")?;
219 }
220 ParserErrorReason::Expected(expected) => {
221 f.write_str(&format!("Expected: {}", expected))?;
222 }
223 ParserErrorReason::BadLiteral => {
224 f.write_str("Malformed literal.")?;
225 }
226 ParserErrorReason::CapturesInUnit => {
227 f.write_str("Cannot have a capture section for a unit struct or variant.")?;
228 }
229 }
230 Ok(())
231 }
232}
233
234pub(crate) fn get_reason(err: &mut nom::Err<ParseError>) -> &mut Option<ParserErrorReason> {
235 match err {
236 nom::Err::Error(err) | nom::Err::Failure(err) => &mut err.reason,
237 nom::Err::Incomplete(_) => panic!("Incomplete not possible"),
238 }
239}