blob: 4c02461c04620dd8de624b667ac941f324ccce4d [file] [log] [blame]
/// Try a list of parsers and return the result of the first successful one
///
/// ```rust,ignore
/// alt!(I -> IResult<I,O> | I -> IResult<I,O> | ... | I -> IResult<I,O> ) => I -> IResult<I, O>
/// ```
/// All the parsers must have the same return type.
///
/// If one of the parsers returns `Incomplete`, `alt!` will return `Incomplete`, to retry
/// once you get more input. Note that it is better for performance to know the
/// minimum size of data you need before you get into `alt!`.
///
/// The `alt!` combinator is used in the following way:
///
/// ```rust,ignore
/// alt!(parser_1 | parser_2 | ... | parser_n)
/// ```
///
/// # Basic example
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
/// // Create a parser that will match either "dragon" or "beast"
/// named!( dragon_or_beast, alt!( tag!( "dragon" ) | tag!( "beast" ) ) );
///
/// // Given the input "dragon slayer", the parser will match "dragon"
/// // and the rest will be " slayer"
/// let (rest, result) = dragon_or_beast(b"dragon slayer").unwrap();
/// assert_eq!(result, b"dragon");
/// assert_eq!(rest, b" slayer");
///
/// // Given the input "beast of Gevaudan", the parser will match "beast"
/// // and the rest will be " of Gevaudan"
/// let (rest, result) = dragon_or_beast(&b"beast of Gevaudan"[..]).unwrap();
/// assert_eq!(result, b"beast");
/// assert_eq!(rest, b" of Gevaudan");
/// # }
/// ```
///
/// # Manipulate results
///
/// There exists another syntax for `alt!` that gives you the ability to
/// manipulate the result from each parser:
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
/// #
/// // We create an enum to represent our creatures
/// #[derive(Debug,PartialEq,Eq)]
/// enum Creature {
/// Dragon,
/// Beast,
/// Unknown(usize)
/// }
///
/// // Let's make a helper function that returns true when not a space
/// // we are required to do this because the `take_while!` macro is limited
/// // to idents, so we can't negate `ìs_space` at the call site
/// fn is_not_space(c: u8) -> bool { ! nom::character::is_space(c) }
///
/// // Our parser will return the `Dragon` variant when matching "dragon",
/// // the `Beast` variant when matching "beast" and otherwise it will consume
/// // the input until a space is found and return an `Unknown` creature with
/// // the size of it's name.
/// named!(creature<Creature>, alt!(
/// tag!("dragon") => { |_| Creature::Dragon } |
/// tag!("beast") => { |_| Creature::Beast } |
/// take_while!(is_not_space) => { |r: &[u8]| Creature::Unknown(r.len()) }
/// // the closure takes the result as argument if the parser is successful
/// ));
///
/// // Given the input "dragon slayer" the parser will return `Creature::Dragon`
/// // and the rest will be " slayer"
/// let (rest, result) = creature(b"dragon slayer").unwrap();
/// assert_eq!(result, Creature::Dragon);
/// assert_eq!(rest, b" slayer");
///
/// // Given the input "beast of Gevaudan" the parser will return `Creature::Beast`
/// // and the rest will be " of Gevaudan"
/// let (rest, result) = creature(b"beast of Gevaudan").unwrap();
/// assert_eq!(result, Creature::Beast);
/// assert_eq!(rest, b" of Gevaudan");
///
/// // Given the input "demon hunter" the parser will return `Creature::Unknown(5)`
/// // and the rest will be " hunter"
/// let (rest, result) = creature(b"demon hunter").unwrap();
/// assert_eq!(result, Creature::Unknown(5));
/// assert_eq!(rest, b" hunter");
/// # }
/// ```
///
/// # Behaviour of `alt!`
///
/// **BE CAREFUL** there is a case where the behaviour of `alt!` can be confusing:
///
/// when the alternatives have different lengths, like this case:
///
/// ```ignore
/// named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) );
/// ```
///
/// With this parser, if you pass `"abcd"` as input, the first alternative parses it correctly,
/// but if you pass `"efg"`, the first alternative will return `Incomplete`, since it needs an input
/// of 4 bytes. This behaviour of `alt!` is expected: if you get a partial input that isn't matched
/// by the first alternative, but would match if the input was complete, you want `alt!` to indicate
/// that it cannot decide with limited information.
///
/// There are two ways to fix this behaviour. The first one consists in ordering the alternatives
/// by size, like this:
///
/// ```ignore
/// named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) );
/// ```
///
/// With this solution, the largest alternative will be tested last.
///
/// The other solution uses the `complete!` combinator, which transforms an `Incomplete` in an
/// `Error`. If one of the alternatives returns `Incomplete` but is wrapped by `complete!`,
/// `alt!` will try the next alternative. This is useful when you know that
/// you will not get partial input:
///
/// ```ignore
/// named!( test,
/// alt!(
/// complete!( tag!( "abcd" ) ) |
/// complete!( tag!( "ef" ) ) |
/// complete!( tag!( "ghi" ) ) |
/// complete!( tag!( "kl" ) )
/// )
/// );
/// ```
///
/// This behaviour of `alt!` can get especially confusing if multiple alternatives have different
/// sizes but a common prefix, like this:
///
/// ```ignore
/// named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) );
/// ```
///
/// in that case, if you order by size, passing `"abcd"` as input will always be matched by the
/// smallest parser, so the solution using `complete!` is better suited.
///
/// You can also nest multiple `alt!`, like this:
///
/// ```ignore
/// named!( test,
/// alt!(
/// preceded!(
/// tag!("ab"),
/// alt!(
/// tag!( "cd" ) |
/// eof!()
/// )
/// )
/// | tag!( "ef" )
/// )
/// );
/// ```
///
/// `preceded!` will first parse `"ab"` then, if successful, try the alternatives "cd",
/// or empty input (End Of File). If none of them work, `preceded!` will fail and
/// "ef" will be tested.
///
#[macro_export(local_inner_macros)]
macro_rules! alt (
(__impl $i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)* ) => (
nom_compile_error!("alt uses '|' as separator, not ',':
alt!(
tag!(\"abcd\") |
tag!(\"efgh\") |
tag!(\"ijkl\")
)
");
);
(__impl $i:expr, $e:path, $($rest:tt)* ) => (
alt!(__impl $i, call!($e) , $($rest)*);
);
(__impl $i:expr, $e:path | $($rest:tt)*) => (
alt!(__impl $i, call!($e) | $($rest)*);
);
(__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
let res = $subrule!(i_, $($args)*);
match res {
Ok(o) => Ok(o),
Err(Err::Error(e)) => {
let out = alt!(__impl $i, $($rest)*);
// Compile-time hack to ensure that res's E type is not under-specified.
// This all has no effect at runtime.
#[allow(dead_code)]
fn unify_types<T>(_: &T, _: &T) {}
if let Err(Err::Error(ref e2)) = out {
unify_types(&e, e2);
}
out
},
Err(e) => Err(e),
}
}
);
(__impl $i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;
let i_ = $i.clone();
match $subrule!(i_, $($args)* ) {
Ok((i,o)) => Ok((i,$gen(o))),
Err(Err::Error(e)) => {
let out = alt!(__impl $i, $($rest)*);
// Compile-time hack to ensure that res's E type is not under-specified.
// This all has no effect at runtime.
fn unify_types<T>(_: &T, _: &T) {}
if let Err(Err::Error(ref e2)) = out {
unify_types(&e, e2);
}
out
},
Err(e) => Err(e),
}
}
);
(__impl $i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => (
alt!(__impl $i, call!($e) => { $gen } | $($rest)*);
);
(__impl $i:expr, __end) => (
{
use $crate::{Err,error::ErrorKind};
let e2 = ErrorKind::Alt;
let err = Err::Error(error_position!($i, e2));
Err(err)
}
);
($i:expr, $($rest:tt)*) => (
{
alt!(__impl $i, $($rest)* | __end)
}
);
);
/// `switch!(I -> IResult<I,P>, P => I -> IResult<I,O> | ... | P => I -> IResult<I,O> ) => I -> IResult<I, O>`
/// choose the next parser depending on the result of the first one, if successful,
/// and returns the result of the second parser
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::Err;
/// # use nom::error::ErrorKind;
/// # fn main() {
/// named!(sw,
/// switch!(take!(4),
/// b"abcd" => tag!("XYZ") |
/// b"efgh" => tag!("123")
/// )
/// );
///
/// let a = b"abcdXYZ123";
/// let b = b"abcdef";
/// let c = b"efgh123";
/// let d = b"blah";
///
/// assert_eq!(sw(&a[..]), Ok((&b"123"[..], &b"XYZ"[..])));
/// assert_eq!(sw(&b[..]), Err(Err::Error(error_node_position!(&b"abcdef"[..], ErrorKind::Switch,
/// error_position!(&b"ef"[..], ErrorKind::Tag)))));
/// assert_eq!(sw(&c[..]), Ok((&b""[..], &b"123"[..])));
/// assert_eq!(sw(&d[..]), Err(Err::Error(error_position!(&b"blah"[..], ErrorKind::Switch))));
/// # }
/// ```
///
/// You can specify a default case like with a normal match, using `_`
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
/// named!(sw,
/// switch!(take!(4),
/// b"abcd" => tag!("XYZ") |
/// _ => value!(&b"default"[..])
/// )
/// );
///
/// let a = b"abcdXYZ123";
/// let b = b"blah";
///
/// assert_eq!(sw(&a[..]), Ok((&b"123"[..], &b"XYZ"[..])));
/// assert_eq!(sw(&b[..]), Ok((&b""[..], &b"default"[..])));
/// # }
/// ```
///
/// Due to limitations in Rust macros, it is not possible to have simple functions on the right hand
/// side of pattern, like this:
///
/// ```ignore
/// named!(xyz, tag!("XYZ"));
/// named!(num, tag!("123"));
/// named!(sw,
/// switch!(take!(4),
/// b"abcd" => xyz |
/// b"efgh" => 123
/// )
/// );
/// ```
///
/// If you want to pass your own functions instead, you can use the `call!` combinator as follows:
///
/// ```ignore
/// named!(xyz, tag!("XYZ"));
/// named!(num, tag!("123"));
/// named!(sw,
/// switch!(take!(4),
/// b"abcd" => call!(xyz) |
/// b"efgh" => call!(num)
/// )
/// );
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! switch (
(__impl $i:expr, $submac:ident!( $($args:tt)* ), $( $($p:pat)|+ => $subrule:ident!( $($args2:tt)* ))|* ) => (
{
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::{Err,error::ErrorKind};
let i_ = $i.clone();
match map!(i_, $submac!($($args)*), Some) {
Err(Err::Error(err)) => {
fn unify_types<T>(_: &T, _: &T) {}
let e1 = ErrorKind::Switch;
let e2 = error_position!($i, e1.clone());
unify_types(&err, &e2);
Err(Err::Error(error_node_position!($i, e1, err)))
},
Err(e) => Err(e),
Ok((i, o)) => {
match o {
$($(Some($p) )|+ => match $subrule!(i, $($args2)*) {
Err(Err::Error(err)) => {
fn unify_types<T>(_: &T, _: &T) {}
let e1 = ErrorKind::Switch;
let e2 = error_position!($i, e1.clone());
unify_types(&err, &e2);
Err(Err::Error(error_node_position!($i, e1, err)))
},
Ok(o) => Ok(o),
Err(e) => Err(e),
}),*,
_ => Err(Err::convert(Err::Error(error_position!($i, ErrorKind::Switch))))
}
}
}
}
);
($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => (
{
switch!(__impl $i, $submac!($($args)*), $($rest)*)
}
);
($i:expr, $e:path, $($rest:tt)*) => (
{
switch!(__impl $i, call!($e), $($rest)*)
}
);
);
///
///
/// `permutation!(I -> IResult<I,A>, I -> IResult<I,B>, ... I -> IResult<I,X> ) => I -> IResult<I, (A,B,...X)>`
/// applies its sub parsers in a sequence, but independent from their order
/// this parser will only succeed if all of its sub parsers succeed
///
/// the tuple of results is in the same order as the parsers are declared
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::ErrorKind,Needed};
/// # fn main() {
/// named!(perm<(&[u8], &[u8], &[u8])>,
/// permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))
/// );
///
/// // whatever the order, if the parser succeeds, each
/// // tag should have matched correctly
/// let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
///
/// let a = &b"abcdefghijk"[..];
/// assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
/// let b = &b"efgabcdhijkl"[..];
/// assert_eq!(perm(b), Ok((&b"jkl"[..], expected)));
/// let c = &b"hiefgabcdjklm"[..];
/// assert_eq!(perm(c), Ok((&b"jklm"[..], expected)));
///
/// let d = &b"efgxyzabcdefghi"[..];
/// assert_eq!(perm(d), Err(Err::Error(error_node_position!(&b"efgxyzabcdefghi"[..], ErrorKind::Permutation,
/// error_position!(&b"xyzabcdefghi"[..], ErrorKind::Permutation)))));
///
/// let e = &b"efgabc"[..];
/// assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4))));
/// # }
/// ```
///
/// If one of the child parsers is followed by a `?`, that parser is now
/// optional:
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::ErrorKind,Needed};
/// # fn main() {
/// named!(perm<&str, (Option<&str>, &str, &str)>,
/// permutation!(tag!("abcd")?, tag!("efg"), tag!("hi"))
/// );
///
/// // whatever the order, if the parser succeeds, each
/// // tag should have matched correctly
/// let expected = (Some("abcd"), "efg", "hi");
///
/// let a = "abcdefghijk";
/// assert_eq!(perm(a), Ok(("jk", expected)));
/// let b = "efgabcdhijkl";
/// assert_eq!(perm(b), Ok(("jkl", expected)));
/// let c = "hiefgabcdjklm";
/// assert_eq!(perm(c), Ok(("jklm", expected)));
///
/// // if `abcd` is missing:
/// let expected = (None, "efg", "hi");
///
/// let a = "efghijk";
/// assert_eq!(perm(a), Ok(("jk", expected)));
/// let b = "efghijkl";
/// assert_eq!(perm(b), Ok(("jkl", expected)));
/// let c = "hiefgjklm";
/// assert_eq!(perm(c), Ok(("jklm", expected)));
///
/// let e = "efgabc";
/// assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4))));
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! permutation (
($i:expr, $($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!(0, input, 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 = 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_init (
((), $e:ident?, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $e:ident, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
((), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
);
(($($parsed:expr),*), $e:ident?, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $e:ident, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
);
(($($parsed:expr),*), $e:ident) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $e:ident?) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )?) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
($($parsed),* , $crate::lib::std::option::Option::None)
);
(($($parsed:expr),*),) => (
($($parsed),*)
);
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! succ (
(0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
(1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
(2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
(3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
(4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
(5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
(6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
(7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
(8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
(9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
(10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
(11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
(12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
(13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
(14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
(15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
(16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
(17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
(18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
(19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_unwrap (
($it:tt, (), $res:ident, $e:ident?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($res.$it), $res, $($rest)*));
);
($it:tt, (), $res:ident, $e:ident, $($rest:tt)*) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($res.$it), $res, $($rest)*));
);
($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($($parsed),* , $res.$it), $res, $($rest)*));
);
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($rest:tt)*) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
succ!($it, permutation_unwrap!(($($parsed),* , $res.$it), $res, $($rest)*));
);
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident?, $e:ident) => (
$crate::lib::std::option::Option::Some(($($parsed),* , { $res.$it }))
);
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident) => ({
let res = $res.$it;
if res.is_some() {
$crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?) => (
$crate::lib::std::option::Option::Some(($($parsed),* , { $res.$it }))
);
($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )) => ({
let res = $res.$it;
if res.is_some() {
$crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
} else {
$crate::lib::std::option::Option::None
}
});
);
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_iterator (
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?, $($rest:tt)*) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
);
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
);
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => {
permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*) , $($rest)*);
};
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;
if $res.$it.is_none() {
match $submac!($i, $($args)*) {
Ok((i,o)) => {
$i = i;
$res.$it = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
$needed = Some(e);
break;
}
};
}
succ!($it, permutation_iterator!($i, $all_done, $needed, $res, $($rest)*));
});
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
);
($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident) => (
permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
);
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?) => {
permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*));
};
($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ({
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;
if $res.$it.is_none() {
match $submac!($i, $($args)*) {
Ok((i,o)) => {
$i = i;
$res.$it = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
$needed = Some(e);
break;
}
};
}
});
);
#[cfg(test)]
mod tests {
use crate::error::ErrorKind;
#[cfg(feature = "alloc")]
use crate::{
error::ParseError,
lib::std::{
fmt::Debug,
string::{String, ToString}
}
};
use crate::internal::{Err, IResult, Needed};
// reproduce the tag and take macros, because of module import order
macro_rules! tag (
($i:expr, $inp: expr) => (
{
#[inline(always)]
fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
b.as_bytes()
}
let expected = $inp;
let bytes = as_bytes(&expected);
tag_bytes!($i,bytes)
}
);
);
macro_rules! tag_bytes (
($i:expr, $bytes: expr) => (
{
use $crate::lib::std::cmp::min;
let len = $i.len();
let blen = $bytes.len();
let m = min(len, blen);
let reduced = &$i[..m];
let b = &$bytes[..m];
let res: IResult<_,_,_> = if reduced != b {
let e: ErrorKind = ErrorKind::Tag;
Err(Err::Error(error_position!($i, e)))
} else if m < blen {
Err(Err::Incomplete(Needed::Size(blen)))
} else {
Ok((&$i[blen..], reduced))
};
res
}
);
);
macro_rules! take(
($i:expr, $count:expr) => (
{
let cnt = $count as usize;
let res:IResult<&[u8],&[u8],_> = if $i.len() < cnt {
Err(Err::Incomplete(Needed::Size(cnt)))
} else {
Ok((&$i[cnt..],&$i[0..cnt]))
};
res
}
);
);
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
pub struct ErrorStr(String);
#[cfg(feature = "alloc")]
impl From<u32> for ErrorStr {
fn from(i: u32) -> Self {
ErrorStr(format!("custom error code: {}", i))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<&'a str> for ErrorStr {
fn from(i: &'a str) -> 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)
}
//named!(alt1, alt!(dont_work | dont_work));
//named!(alt2, alt!(dont_work | work));
//named!(alt3, alt!(dont_work | dont_work | work2 | dont_work));
let a = &b"abcd"[..];
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!(alt4, alt!(tag!("abcd") | tag!("efgh")));
let b = &b"efgh"[..];
assert_eq!(alt4(a), Ok((&b""[..], a)));
assert_eq!(alt4(b), Ok((&b""[..], b)));
// test the alternative syntax
named!(alt5<bool>, alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true }));
assert_eq!(alt5(a), Ok((&b""[..], false)));
assert_eq!(alt5(b), Ok((&b""[..], true)));
// compile-time test guarding against an underspecified E generic type (#474)
named!(alt_eof1, alt!(eof!() | eof!()));
named!(alt_eof2, alt!(eof!() => {|x| x} | eof!() => {|x| x}));
let _ = (alt_eof1, alt_eof2);
}
#[test]
fn alt_incomplete() {
named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def")));
let a = &b""[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(1))));
let a = &b"b"[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(2))));
let a = &b"bcd"[..];
assert_eq!(alt1(a), Ok((&b"d"[..], &b"bc"[..])));
let a = &b"cde"[..];
assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
let a = &b"de"[..];
assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(3))));
let a = &b"defg"[..];
assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..])));
}
#[allow(unused_variables)]
#[test]
fn switch() {
named!(
sw,
switch!(take!(4),
b"abcd" | b"xxxx" => take!(2) |
b"efgh" => take!(4)
)
);
let a = &b"abcdefgh"[..];
assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
let b = &b"efghijkl"[..];
assert_eq!(sw(b), Ok((&b""[..], &b"ijkl"[..])));
let c = &b"afghijkl"[..];
assert_eq!(sw(c), Err(Err::Error(error_position!(&b"afghijkl"[..], ErrorKind::Switch))));
let a = &b"xxxxefgh"[..];
assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
}
#[test]
fn permutation() {
named!(perm<(&[u8], &[u8], &[u8])>, permutation!(tag!("abcd"), tag!("efg"), tag!("hi")));
let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
let a = &b"abcdefghijk"[..];
assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
let b = &b"efgabcdhijk"[..];
assert_eq!(perm(b), Ok((&b"jk"[..], expected)));
let c = &b"hiefgabcdjk"[..];
assert_eq!(perm(c), Ok((&b"jk"[..], expected)));
let d = &b"efgxyzabcdefghi"[..];
assert_eq!(
perm(d),
Err(Err::Error(error_node_position!(
&b"efgxyzabcdefghi"[..],
ErrorKind::Permutation,
error_position!(&b"xyzabcdefghi"[..], ErrorKind::Permutation)
)))
);
let e = &b"efgabc"[..];
assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4))));
}
/*
named!(does_not_compile,
alt!(tag!("abcd"), tag!("efgh"))
);
*/
}