| //! Support for whitespace delimited formats |
| //! |
| //! a lot of textual formats allows spaces and other |
| //! types of separators between tokens. Handling it |
| //! manually with nom means wrapping all parsers |
| //! like this: |
| //! |
| //! ```ignore |
| //! named!(token, delimited!(space, tk, space)); |
| //! ``` |
| //! |
| //! To ease the development of such parsers, you |
| //! can use the whitespace parsing facility, which works |
| //! as follows: |
| //! |
| //! ``` |
| //! # #[macro_use] extern crate nom; |
| //! # fn main() { |
| //! named!(tuple<&[u8], (&[u8], &[u8]) >, |
| //! ws!(tuple!( take!(3), tag!("de") )) |
| //! ); |
| //! |
| //! assert_eq!( |
| //! tuple(&b" \t abc de fg"[..]), |
| //! Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) |
| //! ); |
| //! # } |
| //! ``` |
| //! |
| //! The `ws!` combinator will modify the parser to |
| //! intersperse space parsers everywhere. By default, |
| //! it will consume the following characters: `" \t\r\n"`. |
| //! |
| //! If you want to modify that behaviour, you can make |
| //! your own whitespace wrapper. As an example, if |
| //! you don't want to consume ends of lines, only |
| //! spaces and tabs, you can do it like this: |
| //! |
| //! ``` |
| //! # #[macro_use] extern crate nom; |
| //! named!(pub space, eat_separator!(&b" \t"[..])); |
| //! |
| //! #[macro_export] |
| //! macro_rules! sp ( |
| //! ($i:expr, $($args:tt)*) => ( |
| //! { |
| //! use nom::Err; |
| //! |
| //! match sep!($i, space, $($args)*) { |
| //! Err(e) => Err(e), |
| //! Ok((i1,o)) => { |
| //! match space(i1) { |
| //! Err(e) => Err(Err::convert(e)), |
| //! Ok((i2,_)) => Ok((i2, o)) |
| //! } |
| //! } |
| //! } |
| //! } |
| //! ) |
| //! ); |
| //! |
| //! # fn main() { |
| //! named!(tuple<&[u8], (&[u8], &[u8]) >, |
| //! sp!(tuple!( take!(3), tag!("de") )) |
| //! ); |
| //! |
| //! assert_eq!( |
| //! tuple(&b" \t abc de fg"[..]), |
| //! Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) |
| //! ); |
| //! # } |
| //! ``` |
| //! |
| //! This combinator works by replacing each combinator with |
| //! a version that supports wrapping with separator parsers. |
| //! It will not support the combinators you wrote in your |
| //! own code. You can still manually wrap them with the separator |
| //! you want, or you can copy the macros defined in src/whitespace.rs |
| //! and modify them to support a new combinator: |
| //! |
| //! * copy the combinator's code here, add the _sep suffix |
| //! * add the `$separator:expr` as second argument |
| //! * wrap any sub parsers with sep!($separator, $submac!($($args)*)) |
| //! * reference it in the definition of `sep!` as follows: |
| //! |
| //! ```ignore |
| //! ($i:expr, $separator:path, my_combinator ! ($($rest:tt)*) ) => { |
| //! wrap_sep!($i, |
| //! $separator, |
| //! my_combinator_sep!($separator, $($rest)*) |
| //! ) |
| //! }; |
| //! ``` |
| //! |
| |
| /// applies the separator parser before the other parser |
| #[macro_export(local_inner_macros)] |
| macro_rules! wrap_sep ( |
| ($i:expr, $separator:expr, $submac:ident!( $($args:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| use $crate::{Err,IResult}; |
| |
| fn unify_types<I,O,P,E>(_: &IResult<I,O,E>, _: &IResult<I,P,E>) {} |
| |
| let sep_res = ($separator)($i); |
| match sep_res { |
| Ok((i1,_)) => { |
| let res = $submac!(i1, $($args)*); |
| unify_types(&sep_res, &res); |
| res |
| }, |
| Err(e) => Err(Err::convert(e)), |
| } |
| }); |
| ($i:expr, $separator:expr, $f:expr) => ( |
| wrap_sep!($i, $separator, call!($f)) |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! pair_sep ( |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( |
| tuple!( |
| $i, |
| sep!($separator, $submac!($($args)*)), |
| sep!($separator, $submac2!($($args2)*)) |
| ) |
| ); |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( |
| pair_sep!($i, $separator, $submac!($($args)*), call!($g)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( |
| pair_sep!($i, $separator, call!($f), $submac!($($args)*)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $g:expr) => ( |
| pair_sep!($i, $separator, call!($f), call!($g)); |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! delimited_sep ( |
| ($i:expr, $separator:path, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match tuple_sep!($i, $separator, (), $submac1!($($args1)*), $($rest)+) { |
| Err(e) => Err(e), |
| Ok((remaining, (_,o,_))) => { |
| Ok((remaining, o)) |
| } |
| } |
| }); |
| ($i:expr, $separator:path, $f:expr, $($rest:tt)+) => ( |
| delimited_sep!($i, $separator, call!($f), $($rest)+); |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! separated_pair_sep ( |
| ($i:expr, $separator:path, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match tuple_sep!($i, $separator, (), $submac1!($($args1)*), $($rest)+) { |
| Err(e) => Err(e), |
| Ok((remaining, (o1,_,o2))) => { |
| Ok((remaining, (o1,o2))) |
| } |
| } |
| }); |
| ($i:expr, $separator:path, $f:expr, $($rest:tt)+) => ( |
| separated_pair_sep!($i, $separator, call!($f), $($rest)+); |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! preceded_sep ( |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { |
| Err(e) => Err(e), |
| Ok((remaining, (_,o))) => { |
| Ok((remaining, o)) |
| } |
| } |
| }); |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( |
| preceded_sep!($i, $separator, $submac!($($args)*), call!($g)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( |
| preceded_sep!($i, $separator, call!($f), $submac!($($args)*)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $g:expr) => ( |
| preceded_sep!($i, $separator, call!($f), call!($g)); |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! terminated_sep ( |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { |
| Err(e) => Err(e), |
| Ok((remaining, (o,_))) => { |
| Ok((remaining, o)) |
| } |
| } |
| }); |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( |
| terminated_sep!($i, $separator, $submac!($($args)*), call!($g)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( |
| terminated_sep!($i, $separator, call!($f), $submac!($($args)*)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $g:expr) => ( |
| terminated_sep!($i, $separator, call!($f), call!($g)); |
| ); |
| ); |
| |
| /// Internal parser, do not use directly |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! tuple_sep ( |
| ($i:expr, $separator:path, ($($parsed:tt),*), $e:path, $($rest:tt)*) => ( |
| tuple_sep!($i, $separator, ($($parsed),*), call!($e), $($rest)*); |
| ); |
| ($i:expr, $separator:path, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| tuple_sep!(i, $separator, (o), $($rest)*) |
| } |
| } |
| } |
| ); |
| ($i:expr, $separator:path, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| tuple_sep!(i, $separator, ($($parsed)* , o), $($rest)*) |
| } |
| } |
| } |
| ); |
| ($i:expr, $separator:path, ($($parsed:tt),*), $e:path) => ( |
| tuple_sep!($i, $separator, ($($parsed),*), call!($e)); |
| ); |
| ($i:expr, $separator:path, (), $submac:ident!( $($args:tt)* )) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| Ok((i, (o))) |
| } |
| } |
| } |
| ); |
| ($i:expr, $separator:path, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| Ok((i, ($($parsed),* , o))) |
| } |
| } |
| } |
| ); |
| ($i:expr, $separator:path, ($($parsed:expr),*)) => ( |
| { |
| ::sts::result::Result::Ok(($i, ($($parsed),*))) |
| } |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! do_parse_sep ( |
| (__impl $i:expr, $separator:path, ( $($rest:expr),* )) => ( |
| $crate::lib::std::result::Result::Ok(($i, ( $($rest),* ))) |
| ); |
| |
| (__impl $i:expr, $separator:path, $e:ident >> $($rest:tt)*) => ( |
| do_parse_sep!(__impl $i, $separator, call!($e) >> $($rest)*); |
| ); |
| (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,_)) => { |
| do_parse_sep!(__impl i, $separator, $($rest)*) |
| }, |
| } |
| } |
| ); |
| |
| (__impl $i:expr, $separator:path, $field:ident : $e:ident >> $($rest:tt)*) => ( |
| do_parse_sep!(__impl $i, $separator, $field: call!($e) >> $($rest)*); |
| ); |
| |
| (__impl $i:expr, $separator:path, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| let $field = o; |
| do_parse_sep!(__impl i, $separator, $($rest)*) |
| }, |
| } |
| } |
| ); |
| |
| // ending the chain |
| (__impl $i:expr, $separator:path, $e:ident >> ( $($rest:tt)* )) => ( |
| do_parse_sep!(__impl $i, $separator, call!($e) >> ( $($rest)* )); |
| ); |
| |
| (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,_)) => { |
| Ok((i, ( $($rest)* ))) |
| }, |
| } |
| }); |
| |
| (__impl $i:expr, $separator:path, $field:ident : $e:ident >> ( $($rest:tt)* )) => ( |
| do_parse_sep!(__impl $i, $separator, $field: call!($e) >> ( $($rest)* ) ); |
| ); |
| |
| (__impl $i:expr, $separator:path, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(e) => Err(e), |
| Ok((i,o)) => { |
| let $field = o; |
| Ok((i, ( $($rest)* ))) |
| }, |
| } |
| }); |
| |
| ($i:expr, $separator:path, $($rest:tt)*) => ( |
| { |
| do_parse_sep!(__impl $i, $separator, $($rest)*) |
| } |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! permutation_sep ( |
| ($i:expr, $separator:path, $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::lib::std::option::Option::*; |
| use $crate::{Err,error::ErrorKind}; |
| |
| let mut res = permutation_init!((), $($rest)*); |
| let mut input = $i; |
| let mut error = None; |
| let mut needed = None; |
| |
| loop { |
| let mut all_done = true; |
| permutation_iterator_sep!(0, input, $separator, all_done, needed, res, $($rest)*); |
| |
| //if we reach that part, it means none of the parsers were able to read anything |
| if !all_done { |
| //FIXME: should wrap the error returned by the child parser |
| error = Option::Some(error_position!(input, ErrorKind::Permutation)); |
| } |
| break; |
| } |
| |
| if let Some(need) = needed { |
| Err(Err::convert(need)) |
| } else { |
| if let Some(unwrapped_res) = { permutation_unwrap!(0, (), res, $($rest)*) } { |
| Ok((input, unwrapped_res)) |
| } else { |
| if let Some(e) = error { |
| Err(Err::Error(error_node_position!($i, ErrorKind::Permutation, e))) |
| } else { |
| Err(Err::Error(error_position!($i, ErrorKind::Permutation))) |
| } |
| } |
| } |
| } |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! permutation_iterator_sep ( |
| ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident?, $($rest:tt)*) => ( |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, call!($e), $($rest)*); |
| ); |
| ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => ( |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, call!($e), $($rest)*); |
| ); |
| |
| ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => ({ |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, $submac!($($args)*), $($rest)*); |
| }); |
| ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({ |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| if $res.$it == $crate::lib::std::option::Option::None { |
| match {sep!($i, $separator, $submac!($($args)*))} { |
| Ok((i,o)) => { |
| $i = i; |
| $res.$it = $crate::lib::std::option::Option::Some(o); |
| continue; |
| }, |
| Err(Err::Error(_)) => { |
| $all_done = false; |
| }, |
| Err(e) => { |
| $needed = $crate::lib::std::option::Option::Some(e); |
| break; |
| } |
| }; |
| } |
| succ!($it, permutation_iterator_sep!($i, $separator, $all_done, $needed, $res, $($rest)*)); |
| }); |
| |
| ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident?) => ( |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $res, call!($e)); |
| ); |
| ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident) => ( |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $res, call!($e)); |
| ); |
| |
| ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?) => ({ |
| permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, $submac!($($args)*)); |
| }); |
| ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ({ |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| if $res.$it == $crate::lib::std::option::Option::None { |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Ok((i,o)) => { |
| $i = i; |
| $res.$it = $crate::lib::std::option::Option::Some(o); |
| continue; |
| }, |
| Err(Err::Error(_)) => { |
| $all_done = false; |
| }, |
| Err(e) => { |
| $needed = $crate::lib::std::option::Option::Some(e); |
| break; |
| } |
| }; |
| } |
| }); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! alt_sep ( |
| (__impl $i:expr, $separator:path, $e:path | $($rest:tt)*) => ( |
| alt_sep!(__impl $i, $separator, call!($e) | $($rest)*); |
| ); |
| |
| (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| let res = sep!($i, $separator, $subrule!($($args)*)); |
| match res { |
| Ok((_,_)) => res, |
| Err(Err::Error(_)) => alt_sep!(__impl $i, $separator, $($rest)*), |
| Err(e) => Err(e), |
| } |
| } |
| ); |
| |
| (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| match sep!($i, $separator, $subrule!( $($args)* )) { |
| Ok((i,o)) => Ok((i,$gen(o))), |
| Err(Err::Error(_)) => { |
| alt_sep!(__impl $i, $separator, $($rest)+) |
| }, |
| Err(e) => Err(e), |
| } |
| } |
| ); |
| |
| (__impl $i:expr, $separator:path, $e:path => { $gen:expr } | $($rest:tt)*) => ( |
| alt_sep!(__impl $i, $separator, call!($e) => { $gen } | $($rest)*); |
| ); |
| |
| (__impl $i:expr, $separator:path, $e:path => { $gen:expr }) => ( |
| alt_sep!(__impl $i, $separator, call!($e) => { $gen }); |
| ); |
| |
| (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| match sep!($i, $separator, $subrule!( $($args)* )) { |
| Ok((i,o)) => Ok((i,$gen(o))), |
| Err(Err::Error(e)) => { |
| fn unify_types<T>(_: &T, _: &T) {} |
| let e2 = error_position!($i, $crate::error::ErrorKind::Alt); |
| unify_types(&e, &e2); |
| Err(Err::Error(e2)) |
| }, |
| Err(e) => Err(e), |
| } |
| } |
| ); |
| |
| (__impl $i:expr, $separator:path, $e:path) => ( |
| alt_sep!(__impl $i, $separator, call!($e)); |
| ); |
| |
| (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)*)) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| match sep!($i, $separator, $subrule!( $($args)* )) { |
| Ok((i,o)) => Ok((i,o)), |
| Err(Err::Error(e)) => { |
| fn unify_types<T>(_: &T, _: &T) {} |
| let e2 = error_position!($i, $crate::error::ErrorKind::Alt); |
| unify_types(&e, &e2); |
| Err(Err::Error(e2)) |
| }, |
| Err(e) => Err(e), |
| } |
| } |
| ); |
| |
| (__impl $i:expr) => ({ |
| use $crate::lib::std::result::Result::*; |
| use $crate::{Err,Needed,IResult}; |
| |
| Err(Err::Error(error_position!($i, $crate::error::ErrorKind::Alt))) |
| }); |
| |
| (__impl $i:expr, $separator:path) => ({ |
| use $crate::lib::std::result::Result::*; |
| use $crate::{Err,Needed,IResult}; |
| |
| Err(Err::Error(error_position!($i, $crate::error::ErrorKind::Alt))) |
| }); |
| |
| ($i:expr, $separator:path, $($rest:tt)*) => ( |
| { |
| alt_sep!(__impl $i, $separator, $($rest)*) |
| } |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[macro_export(local_inner_macros)] |
| macro_rules! switch_sep ( |
| (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( |
| { |
| use $crate::lib::std::result::Result::*; |
| use $crate::Err; |
| |
| match sep!($i, $separator, $submac!($($args)*)) { |
| Err(Err::Error(e)) => Err(Err::Error(error_node_position!( |
| $i, $crate::error::ErrorKind::Switch, e |
| ))), |
| Err(Err::Failure(e)) => Err(Err::Failure( |
| error_node_position!($i, $crate::error::ErrorKind::Switch, e))), |
| Err(e) => Err(e), |
| Ok((i, o)) => { |
| match o { |
| $($p => match sep!(i, $separator, $subrule!($($args2)*)) { |
| Err(Err::Error(e)) => Err(Err::Error(error_node_position!( |
| $i, $crate::error::ErrorKind::Switch, e |
| ))), |
| Err(Err::Failure(e)) => Err(Err::Failure( |
| error_node_position!($i, $crate::error::ErrorKind::Switch, e))), |
| a => a, |
| }),*, |
| _ => Err(Err::Error(error_position!($i, $crate::error::ErrorKind::Switch))) |
| } |
| } |
| } |
| } |
| ); |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( |
| { |
| switch_sep!(__impl $i, $separator, $submac!($($args)*), $($rest)*) |
| } |
| ); |
| ($i:expr, $separator:path, $e:path, $($rest:tt)*) => ( |
| { |
| switch_sep!(__impl $i, $separator, call!($e), $($rest)*) |
| } |
| ); |
| ); |
| |
| #[doc(hidden)] |
| #[cfg(feature = "alloc")] |
| #[macro_export(local_inner_macros)] |
| macro_rules! separated_list_sep ( |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( |
| separated_list!( |
| $i, |
| sep!($separator, $submac!($($args)*)), |
| sep!($separator, $submac2!($($args2)*)) |
| ) |
| ); |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( |
| separated_list_sep!($i, $separator, $submac!($($args)*), call!($g)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( |
| separated_list_sep!($i, $separator, call!($f), $submac!($($args)*)); |
| ); |
| ($i:expr, $separator:path, $f:expr, $g:expr) => ( |
| separated_list_sep!($i, $separator, call!($f), call!($g)); |
| ); |
| ); |
| |
| /// helper macros to build a separator parser |
| /// |
| /// ``` |
| /// # #[macro_use] extern crate nom; |
| /// named!(pub space, eat_separator!(&b" \t"[..])); |
| /// # fn main() {} |
| /// ``` |
| #[macro_export(local_inner_macros)] |
| macro_rules! eat_separator ( |
| ($i:expr, $arr:expr) => ( |
| { |
| use $crate::{FindToken, InputTakeAtPosition}; |
| let input = $i; |
| input.split_at_position(|c| !$arr.find_token(c)) |
| } |
| ); |
| ); |
| |
| /// sep is the parser rewriting macro for whitespace separated formats |
| /// |
| /// it takes as argument a space eating function and a parser tree, |
| /// and will intersperse the space parser everywhere |
| /// |
| /// ```ignore |
| /// #[macro_export(local_inner_macros)] |
| /// macro_rules! ws ( |
| /// ($i:expr, $($args:tt)*) => ( |
| /// { |
| /// use sp; |
| /// sep!($i, sp, $($args)*) |
| /// } |
| /// ) |
| /// ); |
| /// ``` |
| #[macro_export(local_inner_macros)] |
| macro_rules! sep ( |
| ($i:expr, $separator:path, tuple ! ($($rest:tt)*) ) => { |
| tuple_sep!($i, $separator, (), $($rest)*) |
| }; |
| ($i:expr, $separator:path, pair ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| pair_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, delimited ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| delimited_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, separated_pair ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| separated_pair_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, preceded ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| preceded_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, terminated ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| terminated_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, do_parse ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| do_parse_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, permutation ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| permutation_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, alt ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| alt_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, switch ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| switch_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, separated_list ! ($($rest:tt)*) ) => { |
| wrap_sep!($i, |
| $separator, |
| separated_list_sep!($separator, $($rest)*) |
| ) |
| }; |
| ($i:expr, $separator:path, many0 ! ($($rest:tt)*) ) => { |
| many0!($i, wrap_sep!($separator, $($rest)*)) |
| }; |
| ($i:expr, $separator:path, many1 ! ($($rest:tt)*) ) => { |
| many1!($i, wrap_sep!($separator, $($rest)*)) |
| }; |
| ($i:expr, $separator:path, return_error!( $($args:tt)* )) => { |
| return_error!($i, wrap_sep!($separator, $($args)*)) |
| }; |
| //FIXME: missing separated_nonempty_list, |
| // many_till, many_m_n, count, count_fixed, fold_many0, fold_many1, |
| // fold_many_m_n |
| ($i:expr, $separator:path, $submac:ident!( $($args:tt)* )) => { |
| wrap_sep!($i, $separator, $submac!($($args)*)) |
| }; |
| ($i:expr, $separator:path, $f:expr) => { |
| wrap_sep!($i, $separator, call!($f)) |
| }; |
| ); |
| |
| /// `ws!(I -> IResult<I,O>) => I -> IResult<I, O>` |
| /// |
| /// transforms a parser to automatically consume |
| /// whitespace between each token. By default, |
| /// it takes the following characters: `" \t\r\n"`. |
| /// |
| /// If you need a whitespace parser consuming a |
| /// different set of characters, you can make |
| /// your own by reusing the `sep!` combinator. |
| /// |
| /// To use `ws!`, pass your parser as argument: |
| /// |
| /// ``` |
| /// # #[macro_use] extern crate nom; |
| /// # fn main() { |
| /// named!(tuple<&[u8], (&[u8], &[u8]) >, |
| /// ws!(tuple!( take!(3), tag!("de") )) |
| /// ); |
| /// |
| /// assert_eq!( |
| /// tuple(&b" \t abc de fg"[..]), |
| /// Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) |
| /// ); |
| /// # } |
| /// ``` |
| /// |
| #[macro_export(local_inner_macros)] |
| #[deprecated(since = "5.0.0", note = "whitespace parsing only works with macros and will not be updated anymore")] |
| macro_rules! ws ( |
| ($i:expr, $($args:tt)*) => ( |
| { |
| use $crate::Err; |
| use $crate::lib::std::result::Result::*; |
| use $crate::character::complete::multispace0; |
| |
| match sep!($i, multispace0, $($args)*) { |
| Err(e) => Err(e), |
| Ok((i1,o)) => { |
| match (multispace0)(i1) { |
| Err(e) => Err(Err::convert(e)), |
| Ok((i2,_)) => Ok((i2, o)) |
| } |
| } |
| } |
| } |
| ) |
| ); |
| |
| #[cfg(test)] |
| #[allow(dead_code)] |
| mod tests { |
| #[cfg(feature = "alloc")] |
| use crate::{ |
| error::ParseError, |
| lib::std::{ |
| string::{String, ToString}, |
| fmt::Debug |
| } |
| }; |
| use crate::internal::{Err, IResult, Needed}; |
| use crate::character::complete::multispace0 as sp; |
| use crate::error::ErrorKind; |
| |
| #[test] |
| fn spaaaaace() { |
| assert_eq!(sp::<_,(_,ErrorKind)>(&b" \t abc "[..]), Ok((&b"abc "[..], &b" \t "[..]))); |
| } |
| |
| #[test] |
| fn tag() { |
| named!(abc, ws!(tag!("abc"))); |
| |
| assert_eq!(abc(&b" \t abc def"[..]), Ok((&b"def"[..], &b"abc"[..]))); |
| } |
| |
| #[test] |
| fn pair() { |
| named!(pair_2<&[u8], (&[u8], &[u8]) >, |
| ws!(pair!( take!(3), tag!("de") )) |
| ); |
| |
| assert_eq!( |
| pair_2(&b" \t abc de fg"[..]), |
| Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) |
| ); |
| } |
| |
| #[test] |
| fn preceded() { |
| named!(prec<&[u8], &[u8] >, |
| ws!(preceded!( take!(3), tag!("de") )) |
| ); |
| |
| assert_eq!(prec(&b" \t abc de fg"[..]), Ok((&b"fg"[..], &b"de"[..]))); |
| } |
| |
| #[test] |
| fn terminated() { |
| named!(term<&[u8], &[u8] >, |
| ws!(terminated!( take!(3), tag!("de") )) |
| ); |
| |
| assert_eq!(term(&b" \t abc de fg"[..]), Ok((&b"fg"[..], &b"abc"[..]))); |
| } |
| |
| #[test] |
| fn tuple() { |
| //trace_macros!(true); |
| named!(tuple_2<&[u8], (&[u8], &[u8]) >, |
| ws!(tuple!( take!(3), tag!("de") )) |
| ); |
| //trace_macros!(false); |
| |
| assert_eq!( |
| tuple_2(&b" \t abc de fg"[..]), |
| Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) |
| ); |
| } |
| |
| #[test] |
| fn levels() { |
| //trace_macros!(true); |
| named!(level_2<&[u8], (&[u8], (&[u8], &[u8])) >, |
| ws!(pair!(take!(3), tuple!( tag!("de"), tag!("fg ") ))) |
| ); |
| //trace_macros!(false); |
| |
| assert_eq!( |
| level_2(&b" \t abc de fg \t hi "[..]), |
| Ok((&b"hi "[..], (&b"abc"[..], (&b"de"[..], &b"fg "[..])))) |
| ); |
| } |
| |
| #[test] |
| fn do_parse() { |
| fn ret_int1(i: &[u8]) -> IResult<&[u8], u8> { |
| Ok((i, 1)) |
| }; |
| fn ret_int2(i: &[u8]) -> IResult<&[u8], u8> { |
| Ok((i, 2)) |
| }; |
| |
| //trace_macros!(true); |
| named!(do_parser<&[u8], (u8, u8)>, |
| ws!(do_parse!( |
| tag!("abcd") >> |
| opt!(tag!("abcd")) >> |
| aa: ret_int1 >> |
| tag!("efgh") >> |
| bb: ret_int2 >> |
| tag!("efgh") >> |
| (aa, bb) |
| )) |
| ); |
| |
| //trace_macros!(false); |
| |
| assert_eq!( |
| do_parser(&b"abcd abcd\tefghefghX"[..]), |
| Ok((&b"X"[..], (1, 2))) |
| ); |
| assert_eq!( |
| do_parser(&b"abcd\tefgh efgh X"[..]), |
| Ok((&b"X"[..], (1, 2))) |
| ); |
| assert_eq!( |
| do_parser(&b"abcd ab"[..]), |
| Err(Err::Incomplete(Needed::Size(4))) |
| ); |
| assert_eq!( |
| do_parser(&b" abcd\tefgh\tef"[..]), |
| Err(Err::Incomplete(Needed::Size(4))) |
| ); |
| } |
| |
| #[test] |
| fn permutation() { |
| //trace_macros!(true); |
| named!( |
| perm<(&[u8], &[u8], &[u8])>, |
| ws!(permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))) |
| ); |
| //trace_macros!(false); |
| |
| let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); |
| |
| let a = &b"abcd\tefg \thijk"[..]; |
| assert_eq!(perm(a), Ok((&b"jk"[..], expected))); |
| let b = &b" efg \tabcdhi jk"[..]; |
| assert_eq!(perm(b), Ok((&b"jk"[..], expected))); |
| let c = &b" hi efg\tabcdjk"[..]; |
| assert_eq!(perm(c), Ok((&b"jk"[..], expected))); |
| |
| let d = &b"efg xyzabcdefghi"[..]; |
| assert_eq!( |
| perm(d), |
| Err(Err::Error(error_node_position!( |
| &b"efg xyzabcdefghi"[..], |
| ErrorKind::Permutation, |
| error_position!(&b" xyzabcdefghi"[..], ErrorKind::Permutation) |
| ))) |
| ); |
| |
| let e = &b" efg \tabc"[..]; |
| assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4)))); |
| } |
| |
| #[cfg(feature = "alloc")] |
| #[derive(Debug, Clone, PartialEq)] |
| pub struct ErrorStr(String); |
| |
| #[cfg(feature = "alloc")] |
| impl<'a> From<(&'a[u8], ErrorKind)> for ErrorStr { |
| fn from(i: (&'a[u8], ErrorKind)) -> Self { |
| ErrorStr(format!("custom error code: {:?}", i)) |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<'a> From<(&'a str, ErrorKind)> for ErrorStr { |
| fn from(i: (&'a str, ErrorKind)) -> Self { |
| ErrorStr(format!("custom error message: {:?}", i)) |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<I: Debug> ParseError<I> for ErrorStr { |
| fn from_error_kind(input: I, kind: ErrorKind) -> Self { |
| ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind)) |
| } |
| |
| fn append(input: I, kind: ErrorKind, other: Self) -> Self { |
| ErrorStr(format!("custom error message: ({:?}, {:?}) - {:?}", input, kind, other)) |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| #[test] |
| fn alt() { |
| fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| Ok((&b""[..], input)) |
| } |
| |
| #[allow(unused_variables)] |
| fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| Err(Err::Error(ErrorStr("abcd".to_string()))) |
| } |
| |
| fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| Ok((input, &b""[..])) |
| } |
| |
| fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| alt!(i, dont_work | dont_work) |
| } |
| fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| alt!(i, dont_work | work) |
| } |
| fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { |
| alt!(i, dont_work | dont_work | work2 | dont_work) |
| } |
| |
| let a = &b"\tabcd"[..]; |
| assert_eq!( |
| alt1(a), |
| Err(Err::Error(error_position!(a, ErrorKind::Alt))) |
| ); |
| assert_eq!(alt2(a), Ok((&b""[..], a))); |
| assert_eq!(alt3(a), Ok((a, &b""[..]))); |
| |
| } |
| |
| named!(str_parse(&str) -> &str, ws!(tag!("test"))); |
| #[allow(unused_variables)] |
| #[test] |
| fn str_test() { |
| assert_eq!(str_parse(" \n test\t a\nb"), Ok(("a\nb", "test"))); |
| } |
| |
| // test whitespace parser generation for alt |
| named!(space, tag!(" ")); |
| #[cfg(feature = "alloc")] |
| named!(pipeline_statement<&[u8], ()>, |
| ws!( |
| do_parse!( |
| tag!("pipeline") >> |
| attributes: delimited!(char!('{'), |
| separated_list!(char!(','), alt!( |
| space | |
| space |
| )), |
| char!('}')) >> |
| |
| ({ |
| let _ = attributes; |
| () |
| }) |
| ) |
| ) |
| ); |
| |
| #[cfg(feature = "alloc")] |
| named!( |
| fail<&[u8]>, |
| map!(many_till!(take!(1), ws!(tag!("."))), |(r, _)| r[0]) |
| ); |
| } |