//! 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(_: &IResult, _: &IResult) {} 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) {} 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) {} 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 -> IResult` /// /// 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 ParseError 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]) ); }