diff options
Diffstat (limited to 'third_party/rust/nom/src/whitespace.rs')
-rw-r--r-- | third_party/rust/nom/src/whitespace.rs | 1077 |
1 files changed, 1077 insertions, 0 deletions
diff --git a/third_party/rust/nom/src/whitespace.rs b/third_party/rust/nom/src/whitespace.rs new file mode 100644 index 0000000000..9ed3f55aad --- /dev/null +++ b/third_party/rust/nom/src/whitespace.rs @@ -0,0 +1,1077 @@ +//! 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]) + ); +} |