#[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)*);
#[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)*);
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)
}
);
);
#[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)*)
}
);
);
#[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 !all_done {
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};
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)
}
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)));
named!(alt5<bool>, alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true }));
assert_eq!(alt5(a), Ok((&b""[..], false)));
assert_eq!(alt5(b), Ok((&b""[..], true)));
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))));
}
}