1use nom::{
14 AsChar, Err, IResult, Input, Offset, Parser,
15 error::{ErrorKind, ParseError},
16};
17
18pub(crate) fn map_err<I, F, G>(
27 mut parser: F,
28 mut map: G,
29) -> impl FnMut(I) -> IResult<I, F::Output, F::Error>
30where
31 F: Parser<I>,
32 G: FnMut(Err<F::Error>) -> Err<F::Error>,
33{
34 move |input: I| parser.parse(input).map_err(&mut map)
35}
36
37pub(crate) fn escaped0<I, Error, F, G>(
48 mut normal: F,
49 control_char: char,
50 mut escapable: G,
51) -> impl FnMut(I) -> IResult<I, I, Error>
52where
53 I: Clone + Offset + Input,
54 <I as Input>::Item: AsChar,
55 F: Parser<I, Error = Error>,
56 G: Parser<I, Error = Error>,
57 Error: ParseError<I>,
58{
59 move |input: I| {
60 let mut i = input.clone();
61 let mut consumed_nothing = false;
62
63 while i.input_len() > 0 {
64 let current_len = i.input_len();
65
66 match (normal.parse(i.clone()), consumed_nothing) {
67 (Ok((i2, _)), false) => {
68 if i2.input_len() == 0 {
69 return Ok((input.take_from(input.input_len()), input));
70 }
71 if i2.input_len() == current_len {
72 consumed_nothing = true;
73 }
74 i = i2;
75 }
76 (Ok(..), true) | (Err(Err::Error(_)), _) => {
77 let next_char = i
78 .iter_elements()
79 .next()
80 .ok_or_else(|| {
81 Err::Error(Error::from_error_kind(
82 i.clone(),
83 ErrorKind::Escaped,
84 ))
85 })?
86 .as_char();
87 if next_char == control_char {
88 let next = control_char.len_utf8();
89 if next >= i.input_len() {
90 return Err(Err::Error(Error::from_error_kind(
91 input,
92 ErrorKind::Escaped,
93 )));
94 }
95 match escapable.parse(i.take_from(next)) {
96 Ok((i2, _)) => {
97 if i2.input_len() == 0 {
98 return Ok((
99 input.take_from(input.input_len()),
100 input,
101 ));
102 }
103 consumed_nothing = false;
104 i = i2;
105 }
106 Err(_) => {
107 return Err(Err::Error(
108 Error::from_error_kind(
109 i,
110 ErrorKind::Escaped,
111 ),
112 ));
113 }
114 }
115 } else {
116 let index = input.offset(&i);
117 return Ok(input.take_split(index));
118 }
119 }
120 (Err(e), _) => {
121 return Err(e);
122 }
123 }
124 }
125
126 Ok((input.take_from(input.input_len()), input))
127 }
128}
129
130#[cfg(test)]
131mod escaped0_spec {
132 use nom::{
133 Err, IResult,
134 bytes::complete::escaped,
135 character::complete::{digit0, digit1, one_of},
136 error::{Error, ErrorKind},
137 };
138
139 use super::escaped0;
140
141 type TestResult<'s> = (
149 IResult<&'s str, &'s str>,
150 IResult<&'s str, &'s str>,
151 IResult<&'s str, &'s str>,
152 IResult<&'s str, &'s str>,
153 );
154
155 fn get_result(input: &str) -> TestResult<'_> {
157 (
158 escaped0(digit0, '\\', one_of(r#""n\"#))(input),
159 escaped0(digit1, '\\', one_of(r#""n\"#))(input),
160 escaped(digit0, '\\', one_of(r#""n\"#))(input),
161 escaped(digit1, '\\', one_of(r#""n\"#))(input),
162 )
163 }
164
165 #[test]
166 fn matches_empty() {
167 assert_eq!(
168 get_result(""),
169 (Ok(("", "")), Ok(("", "")), Ok(("", "")), Ok(("", ""))),
170 );
171 }
172
173 #[test]
174 fn matches_normal() {
175 assert_eq!(
176 get_result("123;"),
177 (
178 Ok((";", "123")),
179 Ok((";", "123")),
180 Ok((";", "123")),
181 Ok((";", "123"))
182 ),
183 );
184 }
185
186 #[test]
187 fn matches_only_escaped() {
188 assert_eq!(
189 get_result(r#"\n\";"#),
190 (
191 Ok((";", r#"\n\""#)),
192 Ok((";", r#"\n\""#)),
193 Ok((r#"\n\";"#, "")),
194 Ok((";", r#"\n\""#)),
195 ),
196 );
197 }
198
199 #[test]
200 fn matches_escaped_followed_by_normal() {
201 assert_eq!(
202 get_result(r#"\n\"123;"#),
203 (
204 Ok((";", r#"\n\"123"#)),
205 Ok((";", r#"\n\"123"#)),
206 Ok((r#"\n\"123;"#, "")),
207 Ok((";", r#"\n\"123"#)),
208 ),
209 );
210 }
211
212 #[test]
213 fn matches_normal_followed_by_escaped() {
214 assert_eq!(
215 get_result(r#"123\n\";"#),
216 (
217 Ok((";", r#"123\n\""#)),
218 Ok((";", r#"123\n\""#)),
219 Ok((r#"\n\";"#, "123")),
220 Ok((";", r#"123\n\""#)),
221 ),
222 );
223 }
224
225 #[test]
226 fn matches_escaped_followed_by_normal_then_escaped() {
227 assert_eq!(
228 get_result(r#"\n\"123\n;"#),
229 (
230 Ok((";", r#"\n\"123\n"#)),
231 Ok((";", r#"\n\"123\n"#)),
232 Ok((r#"\n\"123\n;"#, "")),
233 Ok((";", r#"\n\"123\n"#)),
234 ),
235 );
236 }
237
238 #[test]
239 fn matches_normal_followed_by_escaped_then_normal() {
240 assert_eq!(
241 get_result(r#"123\n\"567;"#),
242 (
243 Ok((";", r#"123\n\"567"#)),
244 Ok((";", r#"123\n\"567"#)),
245 Ok((r#"\n\"567;"#, "123")),
246 Ok((";", r#"123\n\"567"#)),
247 ),
248 );
249 }
250
251 #[test]
252 fn errors_on_escaped_non_reserved() {
253 assert_eq!(
254 get_result(r#"\n\r"#),
255 (
256 Err(Err::Error(Error {
257 input: r#"\r"#,
258 code: ErrorKind::Escaped,
259 })),
260 Err(Err::Error(Error {
261 input: r#"\r"#,
262 code: ErrorKind::Escaped,
263 })),
264 Ok((r#"\n\r"#, "")),
265 Err(Err::Error(Error {
266 input: r#"r"#,
267 code: ErrorKind::OneOf,
268 })),
269 ),
270 );
271 }
272
273 #[test]
274 fn errors_on_ending_with_control_char() {
275 assert_eq!(
276 get_result("\\"),
277 (
278 Err(Err::Error(Error {
279 input: "\\",
280 code: ErrorKind::Escaped,
281 })),
282 Err(Err::Error(Error {
283 input: "\\",
284 code: ErrorKind::Escaped,
285 })),
286 Ok(("\\", "")),
287 Err(Err::Error(Error {
288 input: "\\",
289 code: ErrorKind::Escaped,
290 })),
291 ),
292 );
293 }
294}