#[macro_export]
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_export]
macro_rules! tag_bytes (
($i:expr, $bytes: expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = if $bytes.len() > $i.len() {
$crate::IResult::Incomplete($crate::Needed::Size($bytes.len()))
} else if &$i[0..$bytes.len()] == $bytes {
$crate::IResult::Done(&$i[$bytes.len()..], &$i[0..$bytes.len()])
} else {
$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Tag, $i))
};
res
}
);
);
#[macro_export]
macro_rules! is_not(
($input:expr, $arr:expr) => (
{
#[inline(always)]
fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
b.as_bytes()
}
let expected = $arr;
let bytes = as_bytes(&expected);
is_not_bytes!($input, bytes)
}
);
);
#[macro_export]
macro_rules! is_not_bytes (
($input:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = match $input.iter().position(|c| {
for &i in $bytes.iter() {
if *c == i { return true }
}
false
}) {
Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsNot,$input)),
Some(n) => {
let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
res
},
None => {
$crate::IResult::Done(&b""[..], $input)
}
};
res
}
);
);
#[macro_export]
macro_rules! is_a (
($input:expr, $arr:expr) => (
{
#[inline(always)]
fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
b.as_bytes()
}
let expected = $arr;
let bytes = as_bytes(&expected);
is_a_bytes!($input, bytes)
}
);
);
#[macro_export]
macro_rules! is_a_bytes (
($input:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = match $input.iter().position(|c| {
for &i in $bytes.iter() {
if *c == i { return false }
}
true
}) {
Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsA,$input)),
Some(n) => {
let res: $crate::IResult<&[u8],&[u8]> = $crate::IResult::Done(&$input[n..], &$input[..n]);
res
},
None => {
$crate::IResult::Done(&b""[..], $input)
}
};
res
}
);
);
#[macro_export]
macro_rules! escaped (
($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $escapable:ident!( $($args2:tt)* )) => (
{
let cl = || {
use $crate::HexDisplay;
let mut index = 0;
while index < $i.len() {
if let $crate::IResult::Done(i,_) = $normal!(&$i[index..], $($args)*) {
if i.is_empty() {
return $crate::IResult::Done(&b""[..], $i)
} else {
index = $i.offset(i);
}
} else if $i[index] == $control_char as u8 {
if index + 1 >= $i.len() {
return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..]));
} else {
match $escapable!(&$i[index+1..], $($args2)*) {
$crate::IResult::Done(i,_) => {
if i.is_empty() {
return $crate::IResult::Done(&b""[..], $i)
} else {
index = $i.offset(i);
}
},
$crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i),
$crate::IResult::Error(e) => return $crate::IResult::Error(e)
}
}
} else {
if index == 0 {
return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..]))
} else {
return $crate::IResult::Done(&$i[index..], &$i[..index])
}
}
}
$crate::IResult::Done(&$i[index..], &$i[..index])
};
match cl() {
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
$crate::IResult::Error(e) => {
return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::Escaped, $i, Box::new(e)))
}
}
}
)
);
#[macro_export]
macro_rules! escaped_transform (
($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $transform:ident!( $($args2:tt)* )) => (
{
let cl = || {
use $crate::HexDisplay;
let mut index = 0;
let mut res = Vec::new();
while index < $i.len() {
if let $crate::IResult::Done(i,o) = $normal!(&$i[index..], $($args)*) {
res.extend(o.iter().cloned());
if i.is_empty() {
return $crate::IResult::Done(&b""[..], res)
} else {
index = $i.offset(i);
}
} else if $i[index] == $control_char as u8 {
if index + 1 >= $i.len() {
return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..]));
} else {
match $transform!(&$i[index+1..], $($args2)*) {
$crate::IResult::Done(i,o) => {
res.extend(o.iter().cloned());
if i.is_empty() {
return $crate::IResult::Done(&b""[..], res)
} else {
index = $i.offset(i);
}
},
$crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i),
$crate::IResult::Error(e) => return $crate::IResult::Error(e)
}
}
} else {
if index == 0 {
return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..]))
} else {
return $crate::IResult::Done(&$i[index..], res)
}
}
}
$crate::IResult::Done(&$i[index..], res)
};
match cl() {
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
$crate::IResult::Error(e) => {
return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::EscapedTransform, $i, Box::new(e)))
}
}
}
)
);
#[macro_export]
macro_rules! take_while (
($input:expr, $submac:ident!( $($args:tt)* )) => (
{
match $input.iter().position(|c| !$submac!(*c, $($args)*)) {
Some(n) => {
let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
res
},
None => {
$crate::IResult::Done(&b""[..], $input)
}
}
}
);
($input:expr, $f:expr) => (
take_while!($input, call!($f));
);
);
#[macro_export]
macro_rules! take_while1 (
($input:expr, $submac:ident!( $($args:tt)* )) => (
{
match $input.iter().position(|c| !$submac!(*c, $($args)*)) {
Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1,$input)),
Some(n) => {
let res = $crate::IResult::Done(&$input[n..], &$input[..n]);
res
},
None => {
$crate::IResult::Done(&b""[..], $input)
}
}
}
);
($input:expr, $f:expr) => (
take_while1!($input, call!($f));
);
);
#[macro_export]
macro_rules! take_till (
($input:expr, $submac:ident!( $($args:tt)* )) => (
{
match $input.iter().position(|c| $submac!(c, $($args)*)) {
Some(n) => $crate::IResult::Done(&$input[n..], &$input[..n]),
None => $crate::IResult::Done(&b""[..], $input)
}
}
);
($input:expr, $f:expr) => (
take_till!($input, call!($f));
);
);
#[macro_export]
macro_rules! take(
($i:expr, $count:expr) => (
{
let cnt = $count as usize;
let res: $crate::IResult<&[u8],&[u8]> = if $i.len() < cnt {
$crate::IResult::Incomplete($crate::Needed::Size(cnt))
} else {
$crate::IResult::Done(&$i[cnt..],&$i[0..cnt])
};
res
}
);
);
#[macro_export]
macro_rules! take_str (
( $i:expr, $size:expr ) => ( map_res!($i, take!($size), ::std::str::from_utf8) );
);
#[macro_export]
macro_rules! take_until_and_consume(
($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);
take_until_and_consume_bytes!($i, bytes)
}
);
);
#[macro_export]
macro_rules! take_until_and_consume_bytes (
($i:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = if $bytes.len() > $i.len() {
$crate::IResult::Incomplete($crate::Needed::Size($bytes.len()))
} else {
let mut index = 0;
let mut parsed = false;
for idx in 0..$i.len() {
if idx + $bytes.len() > $i.len() {
index = idx;
break;
}
if &$i[idx..idx + $bytes.len()] == $bytes {
parsed = true;
index = idx;
break;
}
}
if parsed {
$crate::IResult::Done(&$i[(index + $bytes.len())..], &$i[0..index])
} else {
$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilAndConsume,$i))
}
};
res
}
);
);
#[macro_export]
macro_rules! take_until(
($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);
take_until_bytes!($i, bytes)
}
);
);
#[macro_export]
macro_rules! take_until_bytes(
($i:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = if $bytes.len() > $i.len() {
$crate::IResult::Incomplete($crate::Needed::Size($bytes.len()))
} else {
let mut index = 0;
let mut parsed = false;
for idx in 0..$i.len() {
if idx + $bytes.len() > $i.len() {
index = idx;
break;
}
if &$i[idx..idx+$bytes.len()] == $bytes {
parsed = true;
index = idx;
break;
}
}
if parsed {
$crate::IResult::Done(&$i[index..], &$i[0..index])
} else {
$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntil,$i))
}
};
res
}
);
);
#[macro_export]
macro_rules! take_until_either_and_consume(
($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);
take_until_either_and_consume_bytes!($i, bytes)
}
);
);
#[macro_export]
macro_rules! take_until_either_and_consume_bytes(
($i:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = if 1 > $i.len() {
$crate::IResult::Incomplete($crate::Needed::Size(1))
} else {
let mut index = 0;
let mut parsed = false;
for idx in 0..$i.len() {
if idx + 1 > $i.len() {
index = idx;
break;
}
for &t in $bytes.iter() {
if $i[idx] == t {
parsed = true;
index = idx;
break;
}
}
if parsed { break; }
}
if parsed {
$crate::IResult::Done(&$i[(index+1)..], &$i[0..index])
} else {
$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEitherAndConsume,$i))
}
};
res
}
);
);
#[macro_export]
macro_rules! take_until_either(
($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);
take_until_either_bytes!($i, bytes)
}
);
);
#[macro_export]
macro_rules! take_until_either_bytes(
($i:expr, $bytes:expr) => (
{
let res: $crate::IResult<&[u8],&[u8]> = if 1 > $i.len() {
$crate::IResult::Incomplete($crate::Needed::Size(1))
} else {
let mut index = 0;
let mut parsed = false;
for idx in 0..$i.len() {
if idx + 1 > $i.len() {
index = idx;
break;
}
for &t in $bytes.iter() {
if $i[idx] == t {
parsed = true;
index = idx;
break;
}
}
if parsed { break; }
}
if parsed {
$crate::IResult::Done(&$i[index..], &$i[0..index])
} else {
$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEither,$i))
}
};
res
}
);
);
#[macro_export]
macro_rules! length_bytes(
($i:expr, $f:expr) => (
{
match $f($i) {
$crate::IResult::Error(a) => $crate::IResult::Error(a),
$crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
$crate::IResult::Done(i1,nb) => {
let length_remaining = i1.len();
if length_remaining < nb {
$crate::IResult::Incomplete(Needed::Size(nb - length_remaining))
} else {
$crate::IResult::Done(&i1[nb..], &i1[..nb])
}
}
}
}
)
);
#[cfg(test)]
mod tests {
use internal::Needed;
use internal::IResult::*;
use internal::Err::*;
use util::ErrorKind;
#[test]
fn is_a() {
named!(a_or_b, is_a!(&b"ab"[..]));
let a = &b"abcd"[..];
assert_eq!(a_or_b(a), Done(&b"cd"[..], &b"ab"[..]));
let b = &b"bcde"[..];
assert_eq!(a_or_b(b), Done(&b"cde"[..], &b"b"[..]));
let c = &b"cdef"[..];
assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsA,c)));
let d = &b"bacdef"[..];
assert_eq!(a_or_b(d), Done(&b"cdef"[..], &b"ba"[..]));
}
#[test]
fn is_not() {
named!(a_or_b, is_not!(&b"ab"[..]));
let a = &b"cdab"[..];
assert_eq!(a_or_b(a), Done(&b"ab"[..], &b"cd"[..]));
let b = &b"cbde"[..];
assert_eq!(a_or_b(b), Done(&b"bde"[..], &b"c"[..]));
let c = &b"abab"[..];
assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsNot,c)));
let d = &b"cdefba"[..];
assert_eq!(a_or_b(d), Done(&b"ba"[..], &b"cdef"[..]));
let e = &b"e"[..];
assert_eq!(a_or_b(e), Done(&b""[..], &b"e"[..]));
let f = &b"fghi"[..];
assert_eq!(a_or_b(f), Done(&b""[..], &b"fghi"[..]));
}
use nom::alpha;
#[test]
fn escaping() {
named!(esc, escaped!(call!(alpha), '\\', is_a_bytes!(&b"\"n\\"[..])));
assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], &b"abcd"[..]));
assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], &b"ab\\\"cd"[..]));
assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], &b"\\\"abcd"[..]));
assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], &b"\\n"[..]));
assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], &b"ab\\\""[..]));
assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\"[..], Box::new(Position(ErrorKind::Escaped, &b"\\"[..])))));
assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\A"[..], Box::new(Position(ErrorKind::IsA, &b"A"[..])))));
}
fn to_s(i:Vec<u8>) -> String {
String::from_utf8_lossy(&i).into_owned()
}
#[test]
fn escape_transform() {
use std::str;
named!(esc< String >, map!(escaped_transform!(call!(alpha), '\\',
alt!(
tag!("\\") => { |_| &b"\\"[..] }
| tag!("\"") => { |_| &b"\""[..] }
| tag!("n") => { |_| &b"\n"[..] }
)), to_s)
);
assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], String::from("abcd")));
assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], String::from("ab\"cd")));
assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], String::from("\"abcd")));
assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], String::from("\n")));
assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], String::from("ab\"")));
assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\"[..], Box::new(Position(ErrorKind::EscapedTransform, &b"\\"[..])))));
assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\A"[..], Box::new(Position(ErrorKind::Alt, &b"A"[..])))));
let e = "è";
let a = "à";
println!("è: {:?} | à: {:?}", str::as_bytes(e), str::as_bytes(a));
named!(esc2< String >, map!(escaped_transform!(call!(alpha), '&',
alt!(
tag!("egrave;") => { |_| str::as_bytes("è") }
| tag!("agrave;") => { |_| str::as_bytes("à") }
)), to_s)
);
assert_eq!(esc2(&b"abèDEF"[..]), Done(&b""[..], String::from("abèDEF")));
assert_eq!(esc2(&b"abèDàEF"[..]), Done(&b""[..], String::from("abèDàEF")));
}
#[test]
fn issue_84() {
let r0 = is_a!(&b"aaaaefgh"[..], "abcd");
assert_eq!(r0, Done(&b"efgh"[..], &b"aaaa"[..]));
let r1 = is_a!(&b"aaaa"[..], "abcd");
assert_eq!(r1, Done(&b""[..], &b"aaaa"[..]));
let r2 = is_a!(&b"1"[..], "123456789");
assert_eq!(r2, Done(&b""[..], &b"1"[..]));
}
#[test]
fn take_str_test() {
let a = b"omnomnom";
assert_eq!(take_str!(&a[..], 5), Done(&b"nom"[..], "omnom"));
assert_eq!(take_str!(&a[..], 9), Incomplete(Needed::Size(9)));
}
#[test]
fn take_until_test() {
named!(x, take_until_and_consume!("efgh"));
let r = x(&b"abcdabcdefghijkl"[..]);
assert_eq!(r, Done(&b"ijkl"[..], &b"abcdabcd"[..]));
println!("Done 1\n");
let r2 = x(&b"abcdabcdefgh"[..]);
assert_eq!(r2, Done(&b""[..], &b"abcdabcd"[..]));
println!("Done 2\n");
let r3 = x(&b"abcefg"[..]);
assert_eq!(r3, Error(Position(ErrorKind::TakeUntilAndConsume, &b"abcefg"[..])));
assert_eq!(
x(&b"ab"[..]),
Incomplete(Needed::Size(4))
);
}
#[test]
fn take_until_either_incomplete() {
named!(x, take_until_either!("!."));
assert_eq!(
x(&b"123"[..]),
Error(Position(ErrorKind::TakeUntilEither, &b"123"[..]))
);
}
#[test]
fn take_until_incomplete() {
named!(y, take_until!("end"));
assert_eq!(
y(&b"nd"[..]),
Incomplete(Needed::Size(3))
);
assert_eq!(
y(&b"123"[..]),
Error(Position(ErrorKind::TakeUntil, &b"123"[..]))
);
}
#[cfg(feature = "nightly")]
use test::Bencher;
#[cfg(feature = "nightly")]
#[bench]
fn take_while(b: &mut Bencher) {
use nom::is_alphabetic;
named!(f, take_while!(is_alphabetic));
b.iter(|| {
f(&b"abcdefghijklABCDEejfrfrjgro12aa"[..])
});
}
}