]>
Commit | Line | Data |
---|---|---|
0a29b90c FG |
1 | //! Parsers recognizing bytes streams, complete input version |
2 | ||
3 | #![allow(deprecated)] | |
4 | ||
5 | use crate::error::ErrorKind; | |
6 | use crate::error::ParseError; | |
7 | use crate::input::{ | |
8 | Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, | |
9 | InputTakeAtPosition, IntoOutput, Slice, ToUsize, | |
10 | }; | |
11 | use crate::lib::std::ops::RangeFrom; | |
12 | use crate::lib::std::result::Result::*; | |
13 | use crate::IntoOutputIResult; | |
14 | use crate::{Err, IResult, Parser}; | |
15 | ||
16 | pub(crate) fn any<I, E: ParseError<I>>(input: I) -> IResult<I, <I as InputIter>::Item, E> | |
17 | where | |
18 | I: InputIter + InputLength + Slice<RangeFrom<usize>>, | |
19 | { | |
20 | let mut it = input.iter_indices(); | |
21 | match it.next() { | |
22 | None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))), | |
23 | Some((_, c)) => match it.next() { | |
24 | None => Ok((input.slice(input.input_len()..), c)), | |
25 | Some((idx, _)) => Ok((input.slice(idx..), c)), | |
26 | }, | |
27 | } | |
28 | } | |
29 | ||
30 | /// Recognizes a pattern | |
31 | /// | |
32 | /// The input data will be compared to the tag combinator's argument and will return the part of | |
33 | /// the input that matches the argument | |
34 | /// | |
35 | /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern | |
36 | /// # Example | |
37 | /// ```rust | |
38 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
39 | /// use nom8::bytes::complete::tag; | |
40 | /// | |
41 | /// fn parser(s: &str) -> IResult<&str, &str> { | |
42 | /// tag("Hello")(s) | |
43 | /// } | |
44 | /// | |
45 | /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); | |
46 | /// assert_eq!(parser("Something"), Err(Err::Error(Error::new("Something", ErrorKind::Tag)))); | |
47 | /// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag)))); | |
48 | /// ``` | |
49 | /// | |
50 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::tag`][crate::bytes::tag] | |
51 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::tag`")] | |
52 | pub fn tag<T, Input, Error: ParseError<Input>>( | |
53 | tag: T, | |
54 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
55 | where | |
56 | Input: InputTake + Compare<T>, | |
57 | Input: IntoOutput, | |
58 | T: InputLength + Clone, | |
59 | { | |
60 | move |i: Input| tag_internal(i, tag.clone()) | |
61 | } | |
62 | ||
63 | pub(crate) fn tag_internal<T, Input, Error: ParseError<Input>>( | |
64 | i: Input, | |
65 | t: T, | |
66 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
67 | where | |
68 | Input: InputTake + Compare<T>, | |
69 | Input: IntoOutput, | |
70 | T: InputLength, | |
71 | { | |
72 | let tag_len = t.input_len(); | |
73 | let res: IResult<_, _, Error> = match i.compare(t) { | |
74 | CompareResult::Ok => Ok(i.take_split(tag_len)), | |
75 | _ => { | |
76 | let e: ErrorKind = ErrorKind::Tag; | |
77 | Err(Err::Error(Error::from_error_kind(i, e))) | |
78 | } | |
79 | }; | |
80 | res.into_output() | |
81 | } | |
82 | ||
83 | /// Recognizes a case insensitive pattern. | |
84 | /// | |
85 | /// The input data will be compared to the tag combinator's argument and will return the part of | |
86 | /// the input that matches the argument with no regard to case. | |
87 | /// | |
88 | /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern. | |
89 | /// # Example | |
90 | /// ```rust | |
91 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
92 | /// use nom8::bytes::complete::tag_no_case; | |
93 | /// | |
94 | /// fn parser(s: &str) -> IResult<&str, &str> { | |
95 | /// tag_no_case("hello")(s) | |
96 | /// } | |
97 | /// | |
98 | /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); | |
99 | /// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); | |
100 | /// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); | |
101 | /// assert_eq!(parser("Something"), Err(Err::Error(Error::new("Something", ErrorKind::Tag)))); | |
102 | /// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag)))); | |
103 | /// ``` | |
104 | /// | |
105 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::tag_no_case`][crate::bytes::tag_no_case] | |
106 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::tag_no_case`")] | |
107 | pub fn tag_no_case<T, Input, Error: ParseError<Input>>( | |
108 | tag: T, | |
109 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
110 | where | |
111 | Input: InputTake + Compare<T>, | |
112 | Input: IntoOutput, | |
113 | T: InputLength + Clone, | |
114 | { | |
115 | move |i: Input| tag_no_case_internal(i, tag.clone()) | |
116 | } | |
117 | ||
118 | pub(crate) fn tag_no_case_internal<T, Input, Error: ParseError<Input>>( | |
119 | i: Input, | |
120 | t: T, | |
121 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
122 | where | |
123 | Input: InputTake + Compare<T>, | |
124 | Input: IntoOutput, | |
125 | T: InputLength, | |
126 | { | |
127 | let tag_len = t.input_len(); | |
128 | ||
129 | let res: IResult<_, _, Error> = match (i).compare_no_case(t) { | |
130 | CompareResult::Ok => Ok(i.take_split(tag_len)), | |
131 | _ => { | |
132 | let e: ErrorKind = ErrorKind::Tag; | |
133 | Err(Err::Error(Error::from_error_kind(i, e))) | |
134 | } | |
135 | }; | |
136 | res.into_output() | |
137 | } | |
138 | ||
139 | pub(crate) fn one_of_internal<I, T, E: ParseError<I>>( | |
140 | input: I, | |
141 | list: &T, | |
142 | ) -> IResult<I, <I as InputIter>::Item, E> | |
143 | where | |
144 | I: Slice<RangeFrom<usize>> + InputIter + InputLength, | |
145 | <I as InputIter>::Item: Copy, | |
146 | T: FindToken<<I as InputIter>::Item>, | |
147 | { | |
148 | let mut it = input.iter_indices(); | |
149 | match it.next() { | |
150 | Some((_, c)) if list.find_token(c) => match it.next() { | |
151 | None => Ok((input.slice(input.input_len()..), c)), | |
152 | Some((idx, _)) => Ok((input.slice(idx..), c)), | |
153 | }, | |
154 | Some(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::OneOf))), | |
155 | None => Err(Err::Error(E::from_error_kind(input, ErrorKind::OneOf))), | |
156 | } | |
157 | } | |
158 | ||
159 | pub(crate) fn none_of_internal<I, T, E: ParseError<I>>( | |
160 | input: I, | |
161 | list: &T, | |
162 | ) -> IResult<I, <I as InputIter>::Item, E> | |
163 | where | |
164 | I: Slice<RangeFrom<usize>> + InputIter + InputLength, | |
165 | <I as InputIter>::Item: Copy, | |
166 | T: FindToken<<I as InputIter>::Item>, | |
167 | { | |
168 | let mut it = input.iter_indices(); | |
169 | match it.next() { | |
170 | Some((_, c)) if !list.find_token(c) => match it.next() { | |
171 | None => Ok((input.slice(input.input_len()..), c)), | |
172 | Some((idx, _)) => Ok((input.slice(idx..), c)), | |
173 | }, | |
174 | Some(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::NoneOf))), | |
175 | None => Err(Err::Error(E::from_error_kind(input, ErrorKind::NoneOf))), | |
176 | } | |
177 | } | |
178 | ||
179 | /// Parse till certain characters are met. | |
180 | /// | |
181 | /// The parser will return the longest slice till one of the characters of the combinator's argument are met. | |
182 | /// | |
183 | /// It doesn't consume the matched character. | |
184 | /// | |
185 | /// It will return a `Err::Error(("", ErrorKind::IsNot))` if the pattern wasn't met. | |
186 | /// # Example | |
187 | /// ```rust | |
188 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
189 | /// use nom8::bytes::complete::is_not; | |
190 | /// | |
191 | /// fn not_space(s: &str) -> IResult<&str, &str> { | |
192 | /// is_not(" \t\r\n")(s) | |
193 | /// } | |
194 | /// | |
195 | /// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); | |
196 | /// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); | |
197 | /// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); | |
198 | /// assert_eq!(not_space(""), Err(Err::Error(Error::new("", ErrorKind::IsNot)))); | |
199 | /// ``` | |
200 | /// | |
201 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till1`][crate::bytes::take_till1] | |
202 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till1`")] | |
203 | pub fn is_not<T, Input, Error: ParseError<Input>>( | |
204 | arr: T, | |
205 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
206 | where | |
207 | Input: InputTakeAtPosition, | |
208 | Input: IntoOutput, | |
209 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
210 | { | |
211 | move |i: Input| is_not_internal(i, &arr) | |
212 | } | |
213 | ||
214 | pub(crate) fn is_not_internal<T, Input, Error: ParseError<Input>>( | |
215 | i: Input, | |
216 | arr: &T, | |
217 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
218 | where | |
219 | Input: InputTakeAtPosition, | |
220 | Input: IntoOutput, | |
221 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
222 | { | |
223 | let e: ErrorKind = ErrorKind::IsNot; | |
224 | i.split_at_position1_complete(|c| arr.find_token(c), e) | |
225 | .into_output() | |
226 | } | |
227 | ||
228 | /// Returns the longest slice of the matches the pattern. | |
229 | /// | |
230 | /// The parser will return the longest slice consisting of the characters in provided in the | |
231 | /// combinator's argument. | |
232 | /// | |
233 | /// It will return a `Err(Err::Error((_, ErrorKind::IsA)))` if the pattern wasn't met. | |
234 | /// # Example | |
235 | /// ```rust | |
236 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
237 | /// use nom8::bytes::complete::is_a; | |
238 | /// | |
239 | /// fn hex(s: &str) -> IResult<&str, &str> { | |
240 | /// is_a("1234567890ABCDEF")(s) | |
241 | /// } | |
242 | /// | |
243 | /// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); | |
244 | /// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); | |
245 | /// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); | |
246 | /// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); | |
247 | /// assert_eq!(hex(""), Err(Err::Error(Error::new("", ErrorKind::IsA)))); | |
248 | /// ``` | |
249 | /// | |
250 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while1`][crate::bytes::take_while1`] | |
251 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while1`")] | |
252 | pub fn is_a<T, Input, Error: ParseError<Input>>( | |
253 | arr: T, | |
254 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
255 | where | |
256 | Input: InputTakeAtPosition, | |
257 | Input: IntoOutput, | |
258 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
259 | { | |
260 | move |i: Input| is_a_internal(i, &arr) | |
261 | } | |
262 | ||
263 | pub(crate) fn is_a_internal<T, Input, Error: ParseError<Input>>( | |
264 | i: Input, | |
265 | arr: &T, | |
266 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
267 | where | |
268 | Input: InputTakeAtPosition, | |
269 | Input: IntoOutput, | |
270 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
271 | { | |
272 | let e: ErrorKind = ErrorKind::IsA; | |
273 | i.split_at_position1_complete(|c| !arr.find_token(c), e) | |
274 | .into_output() | |
275 | } | |
276 | ||
277 | /// Returns the longest input slice (if any) that matches the predicate. | |
278 | /// | |
279 | /// The parser will return the longest slice that matches the given predicate *(a function that | |
280 | /// takes the input and returns a bool)*. | |
281 | /// # Example | |
282 | /// ```rust | |
283 | /// # use nom8::{Err, error::ErrorKind, Needed, IResult}; | |
284 | /// use nom8::bytes::complete::take_while; | |
285 | /// use nom8::input::AsChar; | |
286 | /// | |
287 | /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { | |
288 | /// take_while(AsChar::is_alpha)(s) | |
289 | /// } | |
290 | /// | |
291 | /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); | |
292 | /// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); | |
293 | /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); | |
294 | /// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); | |
295 | /// ``` | |
296 | /// | |
297 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while`][crate::bytes::take_while] | |
298 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while`")] | |
299 | pub fn take_while<T, Input, Error: ParseError<Input>>( | |
300 | list: T, | |
301 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
302 | where | |
303 | Input: InputTakeAtPosition, | |
304 | Input: IntoOutput, | |
305 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
306 | { | |
307 | move |i: Input| take_while_internal(i, &list) | |
308 | } | |
309 | ||
310 | pub(crate) fn take_while_internal<T, Input, Error: ParseError<Input>>( | |
311 | i: Input, | |
312 | list: &T, | |
313 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
314 | where | |
315 | Input: InputTakeAtPosition, | |
316 | Input: IntoOutput, | |
317 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
318 | { | |
319 | i.split_at_position_complete(|c| !list.find_token(c)) | |
320 | .into_output() | |
321 | } | |
322 | ||
323 | /// Returns the longest (at least 1) input slice that matches the predicate. | |
324 | /// | |
325 | /// The parser will return the longest slice that matches the given predicate *(a function that | |
326 | /// takes the input and returns a bool)*. | |
327 | /// | |
328 | /// It will return an `Err(Err::Error((_, ErrorKind::TakeWhile1)))` if the pattern wasn't met. | |
329 | /// # Example | |
330 | /// ```rust | |
331 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
332 | /// use nom8::bytes::complete::take_while1; | |
333 | /// use nom8::input::AsChar; | |
334 | /// | |
335 | /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { | |
336 | /// take_while1(AsChar::is_alpha)(s) | |
337 | /// } | |
338 | /// | |
339 | /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); | |
340 | /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); | |
341 | /// assert_eq!(alpha(b"12345"), Err(Err::Error(Error::new(&b"12345"[..], ErrorKind::TakeWhile1)))); | |
342 | /// ``` | |
343 | /// | |
344 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while1`][crate::bytes::take_while1] | |
345 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while1`")] | |
346 | pub fn take_while1<T, Input, Error: ParseError<Input>>( | |
347 | list: T, | |
348 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
349 | where | |
350 | Input: InputTakeAtPosition, | |
351 | Input: IntoOutput, | |
352 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
353 | { | |
354 | move |i: Input| take_while1_internal(i, &list) | |
355 | } | |
356 | ||
357 | pub(crate) fn take_while1_internal<T, Input, Error: ParseError<Input>>( | |
358 | i: Input, | |
359 | list: &T, | |
360 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
361 | where | |
362 | Input: InputTakeAtPosition, | |
363 | Input: IntoOutput, | |
364 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
365 | { | |
366 | let e: ErrorKind = ErrorKind::TakeWhile1; | |
367 | i.split_at_position1_complete(|c| !list.find_token(c), e) | |
368 | .into_output() | |
369 | } | |
370 | ||
371 | /// Returns the longest (m <= len <= n) input slice that matches the predicate. | |
372 | /// | |
373 | /// The parser will return the longest slice that matches the given predicate *(a function that | |
374 | /// takes the input and returns a bool)*. | |
375 | /// | |
376 | /// It will return an `Err::Error((_, ErrorKind::TakeWhileMN))` if the pattern wasn't met or is out | |
377 | /// of range (m <= len <= n). | |
378 | /// # Example | |
379 | /// ```rust | |
380 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
381 | /// use nom8::bytes::complete::take_while_m_n; | |
382 | /// use nom8::input::AsChar; | |
383 | /// | |
384 | /// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { | |
385 | /// take_while_m_n(3, 6, AsChar::is_alpha)(s) | |
386 | /// } | |
387 | /// | |
388 | /// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); | |
389 | /// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); | |
390 | /// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); | |
391 | /// assert_eq!(short_alpha(b"ed"), Err(Err::Error(Error::new(&b"ed"[..], ErrorKind::TakeWhileMN)))); | |
392 | /// assert_eq!(short_alpha(b"12345"), Err(Err::Error(Error::new(&b"12345"[..], ErrorKind::TakeWhileMN)))); | |
393 | /// ``` | |
394 | /// | |
395 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while_m_n`][crate::bytes::take_while_m_n] | |
396 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while_m_n`")] | |
397 | pub fn take_while_m_n<T, Input, Error: ParseError<Input>>( | |
398 | m: usize, | |
399 | n: usize, | |
400 | list: T, | |
401 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
402 | where | |
403 | Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>, | |
404 | Input: IntoOutput, | |
405 | T: FindToken<<Input as InputIter>::Item>, | |
406 | { | |
407 | move |i: Input| take_while_m_n_internal(i, m, n, &list) | |
408 | } | |
409 | ||
410 | pub(crate) fn take_while_m_n_internal<T, Input, Error: ParseError<Input>>( | |
411 | input: Input, | |
412 | m: usize, | |
413 | n: usize, | |
414 | list: &T, | |
415 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
416 | where | |
417 | Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>, | |
418 | Input: IntoOutput, | |
419 | T: FindToken<<Input as InputIter>::Item>, | |
420 | { | |
421 | match input.position(|c| !list.find_token(c)) { | |
422 | Some(idx) => { | |
423 | if idx >= m { | |
424 | if idx <= n { | |
425 | let res: IResult<_, _, Error> = if let Ok(index) = input.slice_index(idx) { | |
426 | Ok(input.take_split(index)).into_output() | |
427 | } else { | |
428 | Err(Err::Error(Error::from_error_kind( | |
429 | input, | |
430 | ErrorKind::TakeWhileMN, | |
431 | ))) | |
432 | }; | |
433 | res | |
434 | } else { | |
435 | let res: IResult<_, _, Error> = if let Ok(index) = input.slice_index(n) { | |
436 | Ok(input.take_split(index)).into_output() | |
437 | } else { | |
438 | Err(Err::Error(Error::from_error_kind( | |
439 | input, | |
440 | ErrorKind::TakeWhileMN, | |
441 | ))) | |
442 | }; | |
443 | res | |
444 | } | |
445 | } else { | |
446 | let e = ErrorKind::TakeWhileMN; | |
447 | Err(Err::Error(Error::from_error_kind(input, e))) | |
448 | } | |
449 | } | |
450 | None => { | |
451 | let len = input.input_len(); | |
452 | if len >= n { | |
453 | match input.slice_index(n) { | |
454 | Ok(index) => Ok(input.take_split(index)).into_output(), | |
455 | Err(_needed) => Err(Err::Error(Error::from_error_kind( | |
456 | input, | |
457 | ErrorKind::TakeWhileMN, | |
458 | ))), | |
459 | } | |
460 | } else if len >= m && len <= n { | |
461 | let res: IResult<_, _, Error> = Ok((input.slice(len..), input)); | |
462 | res.into_output() | |
463 | } else { | |
464 | let e = ErrorKind::TakeWhileMN; | |
465 | Err(Err::Error(Error::from_error_kind(input, e))) | |
466 | } | |
467 | } | |
468 | } | |
469 | } | |
470 | ||
471 | /// Returns the longest input slice (if any) till a predicate is met. | |
472 | /// | |
473 | /// The parser will return the longest slice till the given predicate *(a function that | |
474 | /// takes the input and returns a bool)*. | |
475 | /// # Example | |
476 | /// ```rust | |
477 | /// # use nom8::{Err, error::ErrorKind, Needed, IResult}; | |
478 | /// use nom8::bytes::complete::take_till; | |
479 | /// | |
480 | /// fn till_colon(s: &str) -> IResult<&str, &str> { | |
481 | /// take_till(|c| c == ':')(s) | |
482 | /// } | |
483 | /// | |
484 | /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); | |
485 | /// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed | |
486 | /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); | |
487 | /// assert_eq!(till_colon(""), Ok(("", ""))); | |
488 | /// ``` | |
489 | /// | |
490 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till`][crate::bytes::take_till] | |
491 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till`")] | |
492 | pub fn take_till<T, Input, Error: ParseError<Input>>( | |
493 | list: T, | |
494 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
495 | where | |
496 | Input: InputTakeAtPosition, | |
497 | Input: IntoOutput, | |
498 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
499 | { | |
500 | move |i: Input| take_till_internal(i, &list) | |
501 | } | |
502 | ||
503 | pub(crate) fn take_till_internal<T, Input, Error: ParseError<Input>>( | |
504 | i: Input, | |
505 | list: &T, | |
506 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
507 | where | |
508 | Input: InputTakeAtPosition, | |
509 | Input: IntoOutput, | |
510 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
511 | { | |
512 | i.split_at_position_complete(|c| list.find_token(c)) | |
513 | .into_output() | |
514 | } | |
515 | ||
516 | /// Returns the longest (at least 1) input slice till a predicate is met. | |
517 | /// | |
518 | /// The parser will return the longest slice till the given predicate *(a function that | |
519 | /// takes the input and returns a bool)*. | |
520 | /// | |
521 | /// It will return `Err(Err::Error((_, ErrorKind::TakeTill1)))` if the input is empty or the | |
522 | /// predicate matches the first input. | |
523 | /// # Example | |
524 | /// ```rust | |
525 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
526 | /// use nom8::bytes::complete::take_till1; | |
527 | /// | |
528 | /// fn till_colon(s: &str) -> IResult<&str, &str> { | |
529 | /// take_till1(|c| c == ':')(s) | |
530 | /// } | |
531 | /// | |
532 | /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); | |
533 | /// assert_eq!(till_colon(":empty matched"), Err(Err::Error(Error::new(":empty matched", ErrorKind::TakeTill1)))); | |
534 | /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); | |
535 | /// assert_eq!(till_colon(""), Err(Err::Error(Error::new("", ErrorKind::TakeTill1)))); | |
536 | /// ``` | |
537 | /// | |
538 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till1`][crate::bytes::take_till1] | |
539 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till1`")] | |
540 | pub fn take_till1<T, Input, Error: ParseError<Input>>( | |
541 | list: T, | |
542 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
543 | where | |
544 | Input: InputTakeAtPosition, | |
545 | Input: IntoOutput, | |
546 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
547 | { | |
548 | move |i: Input| take_till1_internal(i, &list) | |
549 | } | |
550 | ||
551 | pub(crate) fn take_till1_internal<T, Input, Error: ParseError<Input>>( | |
552 | i: Input, | |
553 | list: &T, | |
554 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
555 | where | |
556 | Input: InputTakeAtPosition, | |
557 | Input: IntoOutput, | |
558 | T: FindToken<<Input as InputTakeAtPosition>::Item>, | |
559 | { | |
560 | let e: ErrorKind = ErrorKind::TakeTill1; | |
561 | i.split_at_position1_complete(|c| list.find_token(c), e) | |
562 | .into_output() | |
563 | } | |
564 | ||
565 | /// Returns an input slice containing the first N input elements (Input[..N]). | |
566 | /// | |
567 | /// It will return `Err(Err::Error((_, ErrorKind::Eof)))` if the input is shorter than the argument. | |
568 | /// # Example | |
569 | /// ```rust | |
570 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
571 | /// use nom8::bytes::complete::take; | |
572 | /// | |
573 | /// fn take6(s: &str) -> IResult<&str, &str> { | |
574 | /// take(6usize)(s) | |
575 | /// } | |
576 | /// | |
577 | /// assert_eq!(take6("1234567"), Ok(("7", "123456"))); | |
578 | /// assert_eq!(take6("things"), Ok(("", "things"))); | |
579 | /// assert_eq!(take6("short"), Err(Err::Error(Error::new("short", ErrorKind::Eof)))); | |
580 | /// assert_eq!(take6(""), Err(Err::Error(Error::new("", ErrorKind::Eof)))); | |
581 | /// ``` | |
582 | /// | |
583 | /// The units that are taken will depend on the input type. For example, for a | |
584 | /// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will | |
585 | /// take that many `u8`'s: | |
586 | /// | |
587 | /// ```rust | |
588 | /// use nom8::error::Error; | |
589 | /// use nom8::bytes::complete::take; | |
590 | /// | |
591 | /// assert_eq!(take::<_, _, Error<_>>(1usize)("💙"), Ok(("", "💙"))); | |
592 | /// assert_eq!(take::<_, _, Error<_>>(1usize)("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref()))); | |
593 | /// ``` | |
594 | /// | |
595 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take`][crate::bytes::take] | |
596 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take`")] | |
597 | pub fn take<C, Input, Error: ParseError<Input>>( | |
598 | count: C, | |
599 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
600 | where | |
601 | Input: InputIter + InputTake, | |
602 | Input: IntoOutput, | |
603 | C: ToUsize, | |
604 | { | |
605 | let c = count.to_usize(); | |
606 | move |i: Input| take_internal(i, c) | |
607 | } | |
608 | ||
609 | pub(crate) fn take_internal<Input, Error: ParseError<Input>>( | |
610 | i: Input, | |
611 | c: usize, | |
612 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
613 | where | |
614 | Input: InputIter + InputTake, | |
615 | Input: IntoOutput, | |
616 | { | |
617 | match i.slice_index(c) { | |
618 | Err(_needed) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Eof))), | |
619 | Ok(index) => Ok(i.take_split(index)).into_output(), | |
620 | } | |
621 | } | |
622 | ||
623 | /// Returns the input slice up to the first occurrence of the pattern. | |
624 | /// | |
625 | /// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))` | |
626 | /// if the pattern wasn't met. | |
627 | /// # Example | |
628 | /// ```rust | |
629 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
630 | /// use nom8::bytes::complete::take_until; | |
631 | /// | |
632 | /// fn until_eof(s: &str) -> IResult<&str, &str> { | |
633 | /// take_until("eof")(s) | |
634 | /// } | |
635 | /// | |
636 | /// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); | |
637 | /// assert_eq!(until_eof("hello, world"), Err(Err::Error(Error::new("hello, world", ErrorKind::TakeUntil)))); | |
638 | /// assert_eq!(until_eof(""), Err(Err::Error(Error::new("", ErrorKind::TakeUntil)))); | |
639 | /// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); | |
640 | /// ``` | |
641 | /// | |
642 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_until`][crate::bytes::take_until] | |
643 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_until`")] | |
644 | pub fn take_until<T, Input, Error: ParseError<Input>>( | |
645 | tag: T, | |
646 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
647 | where | |
648 | Input: InputTake + FindSubstring<T>, | |
649 | Input: IntoOutput, | |
650 | T: InputLength + Clone, | |
651 | { | |
652 | move |i: Input| take_until_internal(i, tag.clone()) | |
653 | } | |
654 | ||
655 | pub(crate) fn take_until_internal<T, Input, Error: ParseError<Input>>( | |
656 | i: Input, | |
657 | t: T, | |
658 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
659 | where | |
660 | Input: InputTake + FindSubstring<T>, | |
661 | Input: IntoOutput, | |
662 | T: InputLength, | |
663 | { | |
664 | let res: IResult<_, _, Error> = match i.find_substring(t) { | |
665 | None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), | |
666 | Some(index) => Ok(i.take_split(index)), | |
667 | }; | |
668 | res.into_output() | |
669 | } | |
670 | ||
671 | /// Returns the non empty input slice up to the first occurrence of the pattern. | |
672 | /// | |
673 | /// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))` | |
674 | /// if the pattern wasn't met. | |
675 | /// # Example | |
676 | /// ```rust | |
677 | /// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult}; | |
678 | /// use nom8::bytes::complete::take_until1; | |
679 | /// | |
680 | /// fn until_eof(s: &str) -> IResult<&str, &str> { | |
681 | /// take_until1("eof")(s) | |
682 | /// } | |
683 | /// | |
684 | /// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); | |
685 | /// assert_eq!(until_eof("hello, world"), Err(Err::Error(Error::new("hello, world", ErrorKind::TakeUntil)))); | |
686 | /// assert_eq!(until_eof(""), Err(Err::Error(Error::new("", ErrorKind::TakeUntil)))); | |
687 | /// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); | |
688 | /// assert_eq!(until_eof("eof"), Err(Err::Error(Error::new("eof", ErrorKind::TakeUntil)))); | |
689 | /// ``` | |
690 | /// | |
691 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_until1`][crate::bytes::take_until1] | |
692 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_until1`")] | |
693 | pub fn take_until1<T, Input, Error: ParseError<Input>>( | |
694 | tag: T, | |
695 | ) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
696 | where | |
697 | Input: InputTake + FindSubstring<T>, | |
698 | Input: IntoOutput, | |
699 | T: InputLength + Clone, | |
700 | { | |
701 | move |i: Input| take_until1_internal(i, tag.clone()) | |
702 | } | |
703 | ||
704 | pub(crate) fn take_until1_internal<T, Input, Error: ParseError<Input>>( | |
705 | i: Input, | |
706 | t: T, | |
707 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
708 | where | |
709 | Input: InputTake + FindSubstring<T>, | |
710 | Input: IntoOutput, | |
711 | T: InputLength, | |
712 | { | |
713 | let res: IResult<_, _, Error> = match i.find_substring(t) { | |
714 | None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), | |
715 | Some(0) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), | |
716 | Some(index) => Ok(i.take_split(index)), | |
717 | }; | |
718 | res.into_output() | |
719 | } | |
720 | ||
721 | /// Matches a byte string with escaped characters. | |
722 | /// | |
723 | /// * The first argument matches the normal characters (it must not accept the control character) | |
724 | /// * The second argument is the control character (like `\` in most languages) | |
725 | /// * The third argument matches the escaped characters | |
726 | /// # Example | |
727 | /// ``` | |
728 | /// # use nom8::{Err, error::ErrorKind, Needed, IResult}; | |
729 | /// # use nom8::character::complete::digit1; | |
730 | /// use nom8::bytes::complete::escaped; | |
731 | /// use nom8::character::complete::one_of; | |
732 | /// | |
733 | /// fn esc(s: &str) -> IResult<&str, &str> { | |
734 | /// escaped(digit1, '\\', one_of(r#""n\"#))(s) | |
735 | /// } | |
736 | /// | |
737 | /// assert_eq!(esc("123;"), Ok((";", "123"))); | |
738 | /// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#))); | |
739 | /// ``` | |
740 | /// | |
741 | /// | |
742 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::escaped`][crate::bytes::escaped] | |
743 | #[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::escaped`")] | |
744 | pub fn escaped<'a, Input: 'a, Error, F, G, O1, O2>( | |
745 | mut normal: F, | |
746 | control_char: char, | |
747 | mut escapable: G, | |
748 | ) -> impl FnMut(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
749 | where | |
750 | Input: Clone | |
751 | + crate::input::Offset | |
752 | + InputLength | |
753 | + InputTake | |
754 | + InputTakeAtPosition | |
755 | + Slice<RangeFrom<usize>> | |
756 | + InputIter, | |
757 | Input: IntoOutput, | |
758 | <Input as InputIter>::Item: crate::input::AsChar, | |
759 | F: Parser<Input, O1, Error>, | |
760 | G: Parser<Input, O2, Error>, | |
761 | Error: ParseError<Input>, | |
762 | { | |
763 | move |input: Input| escaped_internal(input, &mut normal, control_char, &mut escapable) | |
764 | } | |
765 | ||
766 | pub(crate) fn escaped_internal<'a, Input: 'a, Error, F, G, O1, O2>( | |
767 | input: Input, | |
768 | normal: &mut F, | |
769 | control_char: char, | |
770 | escapable: &mut G, | |
771 | ) -> IResult<Input, <Input as IntoOutput>::Output, Error> | |
772 | where | |
773 | Input: Clone | |
774 | + crate::input::Offset | |
775 | + InputLength | |
776 | + InputTake | |
777 | + InputTakeAtPosition | |
778 | + Slice<RangeFrom<usize>> | |
779 | + InputIter, | |
780 | Input: IntoOutput, | |
781 | <Input as InputIter>::Item: crate::input::AsChar, | |
782 | F: Parser<Input, O1, Error>, | |
783 | G: Parser<Input, O2, Error>, | |
784 | Error: ParseError<Input>, | |
785 | { | |
786 | use crate::input::AsChar; | |
787 | ||
788 | let mut i = input.clone(); | |
789 | ||
790 | while i.input_len() > 0 { | |
791 | let current_len = i.input_len(); | |
792 | ||
793 | match normal.parse(i.clone()) { | |
794 | Ok((i2, _)) => { | |
795 | // return if we consumed everything or if the normal parser | |
796 | // does not consume anything | |
797 | if i2.input_len() == 0 { | |
798 | return Ok((input.slice(input.input_len()..), input)).into_output(); | |
799 | } else if i2.input_len() == current_len { | |
800 | let index = input.offset(&i2); | |
801 | return Ok(input.take_split(index)).into_output(); | |
802 | } else { | |
803 | i = i2; | |
804 | } | |
805 | } | |
806 | Err(Err::Error(_)) => { | |
807 | // unwrap() should be safe here since index < $i.input_len() | |
808 | if i.iter_elements().next().unwrap().as_char() == control_char { | |
809 | let next = control_char.len_utf8(); | |
810 | if next >= i.input_len() { | |
811 | return Err(Err::Error(Error::from_error_kind( | |
812 | input, | |
813 | ErrorKind::Escaped, | |
814 | ))); | |
815 | } else { | |
816 | match escapable.parse(i.slice(next..)) { | |
817 | Ok((i2, _)) => { | |
818 | if i2.input_len() == 0 { | |
819 | return Ok((input.slice(input.input_len()..), input)).into_output(); | |
820 | } else { | |
821 | i = i2; | |
822 | } | |
823 | } | |
824 | Err(e) => return Err(e), | |
825 | } | |
826 | } | |
827 | } else { | |
828 | let index = input.offset(&i); | |
829 | if index == 0 { | |
830 | return Err(Err::Error(Error::from_error_kind( | |
831 | input, | |
832 | ErrorKind::Escaped, | |
833 | ))); | |
834 | } | |
835 | return Ok(input.take_split(index)).into_output(); | |
836 | } | |
837 | } | |
838 | Err(e) => { | |
839 | return Err(e); | |
840 | } | |
841 | } | |
842 | } | |
843 | ||
844 | Ok((input.slice(input.input_len()..), input)).into_output() | |
845 | } | |
846 | ||
847 | /// Matches a byte string with escaped characters. | |
848 | /// | |
849 | /// * The first argument matches the normal characters (it must not match the control character) | |
850 | /// * The second argument is the control character (like `\` in most languages) | |
851 | /// * The third argument matches the escaped characters and transforms them | |
852 | /// | |
853 | /// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) | |
854 | /// | |
855 | /// ``` | |
856 | /// # use nom8::{Err, error::ErrorKind, Needed, IResult}; | |
857 | /// # use std::str::from_utf8; | |
858 | /// use nom8::bytes::complete::{escaped_transform, tag}; | |
859 | /// use nom8::character::complete::alpha1; | |
860 | /// use nom8::branch::alt; | |
861 | /// use nom8::combinator::value; | |
862 | /// | |
863 | /// fn parser(input: &str) -> IResult<&str, String> { | |
864 | /// escaped_transform( | |
865 | /// alpha1, | |
866 | /// '\\', | |
867 | /// alt(( | |
868 | /// value("\\", tag("\\")), | |
869 | /// value("\"", tag("\"")), | |
870 | /// value("\n", tag("n")), | |
871 | /// )) | |
872 | /// )(input) | |
873 | /// } | |
874 | /// | |
875 | /// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd")))); | |
876 | /// assert_eq!(parser("ab\\ncd"), Ok(("", String::from("ab\ncd")))); | |
877 | /// ``` | |
878 | #[cfg(feature = "alloc")] | |
879 | /// | |
880 | /// **WARNING:** Deprecated, replaced with [`nom8::bytes::escaped_transform`][crate::bytes::escaped_transform] | |
881 | #[deprecated( | |
882 | since = "8.0.0", | |
883 | note = "Replaced with `nom8::bytes::escaped_transform`" | |
884 | )] | |
885 | pub fn escaped_transform<Input, Error, F, G, O1, O2, ExtendItem, Output>( | |
886 | mut normal: F, | |
887 | control_char: char, | |
888 | mut transform: G, | |
889 | ) -> impl FnMut(Input) -> IResult<Input, Output, Error> | |
890 | where | |
891 | Input: Clone | |
892 | + crate::input::Offset | |
893 | + InputLength | |
894 | + InputTake | |
895 | + InputTakeAtPosition | |
896 | + Slice<RangeFrom<usize>> | |
897 | + InputIter, | |
898 | Input: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
899 | O1: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
900 | O2: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
901 | <Input as InputIter>::Item: crate::input::AsChar, | |
902 | F: Parser<Input, O1, Error>, | |
903 | G: Parser<Input, O2, Error>, | |
904 | Error: ParseError<Input>, | |
905 | { | |
906 | move |input: Input| escaped_transform_internal(input, &mut normal, control_char, &mut transform) | |
907 | } | |
908 | ||
909 | #[cfg(feature = "alloc")] | |
910 | pub(crate) fn escaped_transform_internal<Input, Error, F, G, O1, O2, ExtendItem, Output>( | |
911 | input: Input, | |
912 | normal: &mut F, | |
913 | control_char: char, | |
914 | transform: &mut G, | |
915 | ) -> IResult<Input, Output, Error> | |
916 | where | |
917 | Input: Clone | |
918 | + crate::input::Offset | |
919 | + InputLength | |
920 | + InputTake | |
921 | + InputTakeAtPosition | |
922 | + Slice<RangeFrom<usize>> | |
923 | + InputIter, | |
924 | Input: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
925 | O1: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
926 | O2: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>, | |
927 | <Input as InputIter>::Item: crate::input::AsChar, | |
928 | F: Parser<Input, O1, Error>, | |
929 | G: Parser<Input, O2, Error>, | |
930 | Error: ParseError<Input>, | |
931 | { | |
932 | use crate::input::AsChar; | |
933 | ||
934 | let mut index = 0; | |
935 | let mut res = input.new_builder(); | |
936 | ||
937 | let i = input.clone(); | |
938 | ||
939 | while index < i.input_len() { | |
940 | let current_len = i.input_len(); | |
941 | let remainder = i.slice(index..); | |
942 | match normal.parse(remainder.clone()) { | |
943 | Ok((i2, o)) => { | |
944 | o.extend_into(&mut res); | |
945 | if i2.input_len() == 0 { | |
946 | return Ok((i.slice(i.input_len()..), res)); | |
947 | } else if i2.input_len() == current_len { | |
948 | return Ok((remainder, res)); | |
949 | } else { | |
950 | index = input.offset(&i2); | |
951 | } | |
952 | } | |
953 | Err(Err::Error(_)) => { | |
954 | // unwrap() should be safe here since index < $i.input_len() | |
955 | if remainder.iter_elements().next().unwrap().as_char() == control_char { | |
956 | let next = index + control_char.len_utf8(); | |
957 | let input_len = input.input_len(); | |
958 | ||
959 | if next >= input_len { | |
960 | return Err(Err::Error(Error::from_error_kind( | |
961 | remainder, | |
962 | ErrorKind::EscapedTransform, | |
963 | ))); | |
964 | } else { | |
965 | match transform.parse(i.slice(next..)) { | |
966 | Ok((i2, o)) => { | |
967 | o.extend_into(&mut res); | |
968 | if i2.input_len() == 0 { | |
969 | return Ok((i.slice(i.input_len()..), res)); | |
970 | } else { | |
971 | index = input.offset(&i2); | |
972 | } | |
973 | } | |
974 | Err(e) => return Err(e), | |
975 | } | |
976 | } | |
977 | } else { | |
978 | if index == 0 { | |
979 | return Err(Err::Error(Error::from_error_kind( | |
980 | remainder, | |
981 | ErrorKind::EscapedTransform, | |
982 | ))); | |
983 | } | |
984 | return Ok((remainder, res)); | |
985 | } | |
986 | } | |
987 | Err(e) => return Err(e), | |
988 | } | |
989 | } | |
990 | Ok((input.slice(index..), res)) | |
991 | } | |
992 | ||
993 | #[cfg(test)] | |
994 | mod tests { | |
995 | use super::*; | |
996 | use crate::character::complete::{alpha1 as alpha, digit1 as digit}; | |
997 | #[cfg(feature = "alloc")] | |
998 | use crate::{ | |
999 | branch::alt, | |
1000 | combinator::{map, value}, | |
1001 | lib::std::string::String, | |
1002 | lib::std::vec::Vec, | |
1003 | }; | |
1004 | ||
1005 | #[test] | |
1006 | fn complete_take_while_m_n_utf8_all_matching() { | |
1007 | let result: IResult<&str, &str> = | |
1008 | super::take_while_m_n(1, 4, |c: char| c.is_alphabetic())("øn"); | |
1009 | assert_eq!(result, Ok(("", "øn"))); | |
1010 | } | |
1011 | ||
1012 | #[test] | |
1013 | fn complete_take_while_m_n_utf8_all_matching_substring() { | |
1014 | let result: IResult<&str, &str> = | |
1015 | super::take_while_m_n(1, 1, |c: char| c.is_alphabetic())("øn"); | |
1016 | assert_eq!(result, Ok(("n", "ø"))); | |
1017 | } | |
1018 | ||
1019 | // issue #1336 "escaped hangs if normal parser accepts empty" | |
1020 | fn escaped_string(input: &str) -> IResult<&str, &str> { | |
1021 | use crate::character::complete::{alpha0, one_of}; | |
1022 | escaped(alpha0, '\\', one_of("n"))(input) | |
1023 | } | |
1024 | ||
1025 | // issue #1336 "escaped hangs if normal parser accepts empty" | |
1026 | #[test] | |
1027 | fn escaped_hang() { | |
1028 | escaped_string("7").unwrap(); | |
1029 | escaped_string("a7").unwrap(); | |
1030 | } | |
1031 | ||
1032 | // issue ##1118 escaped does not work with empty string | |
1033 | fn unquote<'a>(input: &'a str) -> IResult<&'a str, &'a str> { | |
1034 | use crate::bytes::complete::*; | |
1035 | use crate::character::complete::*; | |
1036 | use crate::combinator::opt; | |
1037 | use crate::sequence::delimited; | |
1038 | ||
1039 | delimited( | |
1040 | char('"'), | |
1041 | escaped(opt(none_of(r#"\""#)), '\\', one_of(r#"\"rnt"#)), | |
1042 | char('"'), | |
1043 | )(input) | |
1044 | } | |
1045 | ||
1046 | #[test] | |
1047 | fn escaped_hang_1118() { | |
1048 | assert_eq!(unquote(r#""""#), Ok(("", ""))); | |
1049 | } | |
1050 | ||
1051 | #[cfg(feature = "alloc")] | |
1052 | #[allow(unused_variables)] | |
1053 | #[test] | |
1054 | fn escaping() { | |
1055 | use crate::character::complete::one_of; | |
1056 | ||
1057 | fn esc(i: &[u8]) -> IResult<&[u8], &[u8]> { | |
1058 | escaped(alpha, '\\', one_of("\"n\\"))(i) | |
1059 | } | |
1060 | assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..]))); | |
1061 | assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..]))); | |
1062 | assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..]))); | |
1063 | assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..]))); | |
1064 | assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..]))); | |
1065 | assert_eq!( | |
1066 | esc(&b"AB\\"[..]), | |
1067 | Err(Err::Error(error_position!( | |
1068 | &b"AB\\"[..], | |
1069 | ErrorKind::Escaped | |
1070 | ))) | |
1071 | ); | |
1072 | assert_eq!( | |
1073 | esc(&b"AB\\A"[..]), | |
1074 | Err(Err::Error(error_node_position!( | |
1075 | &b"AB\\A"[..], | |
1076 | ErrorKind::Escaped, | |
1077 | error_position!(&b"A"[..], ErrorKind::OneOf) | |
1078 | ))) | |
1079 | ); | |
1080 | ||
1081 | fn esc2(i: &[u8]) -> IResult<&[u8], &[u8]> { | |
1082 | escaped(digit, '\\', one_of("\"n\\"))(i) | |
1083 | } | |
1084 | assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..]))); | |
1085 | } | |
1086 | ||
1087 | #[cfg(feature = "alloc")] | |
1088 | #[test] | |
1089 | fn escaping_str() { | |
1090 | use crate::character::complete::one_of; | |
1091 | ||
1092 | fn esc(i: &str) -> IResult<&str, &str> { | |
1093 | escaped(alpha, '\\', one_of("\"n\\"))(i) | |
1094 | } | |
1095 | assert_eq!(esc("abcd;"), Ok((";", "abcd"))); | |
1096 | assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd"))); | |
1097 | assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd"))); | |
1098 | assert_eq!(esc("\\n;"), Ok((";", "\\n"))); | |
1099 | assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\""))); | |
1100 | assert_eq!( | |
1101 | esc("AB\\"), | |
1102 | Err(Err::Error(error_position!("AB\\", ErrorKind::Escaped))) | |
1103 | ); | |
1104 | assert_eq!( | |
1105 | esc("AB\\A"), | |
1106 | Err(Err::Error(error_node_position!( | |
1107 | "AB\\A", | |
1108 | ErrorKind::Escaped, | |
1109 | error_position!("A", ErrorKind::OneOf) | |
1110 | ))) | |
1111 | ); | |
1112 | ||
1113 | fn esc2(i: &str) -> IResult<&str, &str> { | |
1114 | escaped(digit, '\\', one_of("\"n\\"))(i) | |
1115 | } | |
1116 | assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n"))); | |
1117 | ||
1118 | fn esc3(i: &str) -> IResult<&str, &str> { | |
1119 | escaped(alpha, '\u{241b}', one_of("\"n"))(i) | |
1120 | } | |
1121 | assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd"))); | |
1122 | } | |
1123 | ||
1124 | #[cfg(feature = "alloc")] | |
1125 | fn to_s(i: Vec<u8>) -> String { | |
1126 | String::from_utf8_lossy(&i).into_owned() | |
1127 | } | |
1128 | ||
1129 | #[cfg(feature = "alloc")] | |
1130 | #[test] | |
1131 | fn escape_transform() { | |
1132 | fn esc(i: &[u8]) -> IResult<&[u8], String> { | |
1133 | map( | |
1134 | escaped_transform( | |
1135 | alpha, | |
1136 | '\\', | |
1137 | alt(( | |
1138 | value(&b"\\"[..], tag("\\")), | |
1139 | value(&b"\""[..], tag("\"")), | |
1140 | value(&b"\n"[..], tag("n")), | |
1141 | )), | |
1142 | ), | |
1143 | to_s, | |
1144 | )(i) | |
1145 | } | |
1146 | ||
1147 | assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd")))); | |
1148 | assert_eq!( | |
1149 | esc(&b"ab\\\"cd;"[..]), | |
1150 | Ok((&b";"[..], String::from("ab\"cd"))) | |
1151 | ); | |
1152 | assert_eq!( | |
1153 | esc(&b"\\\"abcd;"[..]), | |
1154 | Ok((&b";"[..], String::from("\"abcd"))) | |
1155 | ); | |
1156 | assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n")))); | |
1157 | assert_eq!( | |
1158 | esc(&b"ab\\\"12"[..]), | |
1159 | Ok((&b"12"[..], String::from("ab\""))) | |
1160 | ); | |
1161 | assert_eq!( | |
1162 | esc(&b"AB\\"[..]), | |
1163 | Err(Err::Error(error_position!( | |
1164 | &b"\\"[..], | |
1165 | ErrorKind::EscapedTransform | |
1166 | ))) | |
1167 | ); | |
1168 | assert_eq!( | |
1169 | esc(&b"AB\\A"[..]), | |
1170 | Err(Err::Error(error_node_position!( | |
1171 | &b"AB\\A"[..], | |
1172 | ErrorKind::EscapedTransform, | |
1173 | error_position!(&b"A"[..], ErrorKind::Tag) | |
1174 | ))) | |
1175 | ); | |
1176 | ||
1177 | fn esc2(i: &[u8]) -> IResult<&[u8], String> { | |
1178 | map( | |
1179 | escaped_transform( | |
1180 | alpha, | |
1181 | '&', | |
1182 | alt(( | |
1183 | value("è".as_bytes(), tag("egrave;")), | |
1184 | value("à".as_bytes(), tag("agrave;")), | |
1185 | )), | |
1186 | ), | |
1187 | to_s, | |
1188 | )(i) | |
1189 | } | |
1190 | assert_eq!( | |
1191 | esc2(&b"abèDEF;"[..]), | |
1192 | Ok((&b";"[..], String::from("abèDEF"))) | |
1193 | ); | |
1194 | assert_eq!( | |
1195 | esc2(&b"abèDàEF;"[..]), | |
1196 | Ok((&b";"[..], String::from("abèDàEF"))) | |
1197 | ); | |
1198 | } | |
1199 | ||
1200 | #[cfg(feature = "std")] | |
1201 | #[test] | |
1202 | fn escape_transform_str() { | |
1203 | fn esc(i: &str) -> IResult<&str, String> { | |
1204 | escaped_transform( | |
1205 | alpha, | |
1206 | '\\', | |
1207 | alt(( | |
1208 | value("\\", tag("\\")), | |
1209 | value("\"", tag("\"")), | |
1210 | value("\n", tag("n")), | |
1211 | )), | |
1212 | )(i) | |
1213 | } | |
1214 | ||
1215 | assert_eq!(esc("abcd;"), Ok((";", String::from("abcd")))); | |
1216 | assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd")))); | |
1217 | assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd")))); | |
1218 | assert_eq!(esc("\\n;"), Ok((";", String::from("\n")))); | |
1219 | assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\"")))); | |
1220 | assert_eq!( | |
1221 | esc("AB\\"), | |
1222 | Err(Err::Error(error_position!( | |
1223 | "\\", | |
1224 | ErrorKind::EscapedTransform | |
1225 | ))) | |
1226 | ); | |
1227 | assert_eq!( | |
1228 | esc("AB\\A"), | |
1229 | Err(Err::Error(error_node_position!( | |
1230 | "AB\\A", | |
1231 | ErrorKind::EscapedTransform, | |
1232 | error_position!("A", ErrorKind::Tag) | |
1233 | ))) | |
1234 | ); | |
1235 | ||
1236 | fn esc2(i: &str) -> IResult<&str, String> { | |
1237 | escaped_transform( | |
1238 | alpha, | |
1239 | '&', | |
1240 | alt((value("è", tag("egrave;")), value("à", tag("agrave;")))), | |
1241 | )(i) | |
1242 | } | |
1243 | assert_eq!(esc2("abèDEF;"), Ok((";", String::from("abèDEF")))); | |
1244 | assert_eq!( | |
1245 | esc2("abèDàEF;"), | |
1246 | Ok((";", String::from("abèDàEF"))) | |
1247 | ); | |
1248 | ||
1249 | fn esc3(i: &str) -> IResult<&str, String> { | |
1250 | escaped_transform( | |
1251 | alpha, | |
1252 | '␛', | |
1253 | alt((value("\0", tag("0")), value("\n", tag("n")))), | |
1254 | )(i) | |
1255 | } | |
1256 | assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n")))); | |
1257 | } | |
1258 | } |