Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Propagated error type. #413

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 35 additions & 25 deletions src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ macro_rules! take_bits (
use std::ops::Div;
//println!("taking {} bits from {:?}", $count, $i);
let (input, bit_offset) = $i;
let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 {
let res : $crate::IResult<(&[u8],usize), $t, _> = if $count == 0 {
$crate::IResult::Done( (input, bit_offset), 0)
} else {
let cnt = ($count as usize + bit_offset).div(8);
Expand Down Expand Up @@ -169,14 +169,14 @@ macro_rules! tag_bits (
$crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
$crate::IResult::Done(i, o) => {
if let $p = o {
let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o);
let res: $crate::IResult<(&[u8],usize),$t,_> = $crate::IResult::Done(i, o);
res
} else {
$crate::IResult::Error(error_position!($crate::ErrorKind::TagBits, $i))
}
},
_ => {
$crate::IResult::Error(error_position!($crate::ErrorKind::TagBits, $i))
$crate::IResult::Error(tag_bits_err) => {
$crate::propagate_error_type(tag_bits_err, $crate::IResult::Error(error_position!($crate::ErrorKind::TagBits, $i)))
}
}
}
Expand All @@ -188,35 +188,45 @@ mod tests {
use internal::{IResult,Needed};
use ErrorKind;

/// specifies type of error (as u32).
fn done<I, O>(i: I, o: O) -> IResult<I, O, u32> {
IResult::Done(i, o)
}

/// specifies type of error (as u32).
fn incomplete<I, O>(n: Needed) -> IResult<I, O, u32> {
IResult::Incomplete(n)
}

#[test]
fn take_bits() {
let input = vec![0b10101010, 0b11110000, 0b00110011];
let sl = &input[..];

assert_eq!(take_bits!( (sl, 0), u8, 0 ), IResult::Done((sl, 0), 0));
assert_eq!(take_bits!( (sl, 0), u8, 8 ), IResult::Done((&sl[1..], 0), 170));
assert_eq!(take_bits!( (sl, 0), u8, 3 ), IResult::Done((&sl[0..], 3), 5));
assert_eq!(take_bits!( (sl, 0), u8, 6 ), IResult::Done((&sl[0..], 6), 42));
assert_eq!(take_bits!( (sl, 1), u8, 1 ), IResult::Done((&sl[0..], 2), 0));
assert_eq!(take_bits!( (sl, 1), u8, 2 ), IResult::Done((&sl[0..], 3), 1));
assert_eq!(take_bits!( (sl, 1), u8, 3 ), IResult::Done((&sl[0..], 4), 2));
assert_eq!(take_bits!( (sl, 6), u8, 3 ), IResult::Done((&sl[1..], 1), 5));
assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
assert_eq!(take_bits!( (sl, 0), u16, 8 ), IResult::Done((&sl[1..], 0), 170));
assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22)));
assert_eq!(take_bits!( (sl, 0), u8, 0 ), done((sl, 0), 0));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you replace IResult::Done with done here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As commented below, type cannot be inferred if macro is used directly from assert_eq!()

assert_eq!(take_bits!( (sl, 0), u8, 8 ), done((&sl[1..], 0), 170));
assert_eq!(take_bits!( (sl, 0), u8, 3 ), done((&sl[0..], 3), 5));
assert_eq!(take_bits!( (sl, 0), u8, 6 ), done((&sl[0..], 6), 42));
assert_eq!(take_bits!( (sl, 1), u8, 1 ), done((&sl[0..], 2), 0));
assert_eq!(take_bits!( (sl, 1), u8, 2 ), done((&sl[0..], 3), 1));
assert_eq!(take_bits!( (sl, 1), u8, 3 ), done((&sl[0..], 4), 2));
assert_eq!(take_bits!( (sl, 6), u8, 3 ), done((&sl[1..], 1), 5));
assert_eq!(take_bits!( (sl, 0), u16, 10 ), done((&sl[1..], 2), 683));
assert_eq!(take_bits!( (sl, 0), u16, 8 ), done((&sl[1..], 0), 170));
assert_eq!(take_bits!( (sl, 6), u16, 10 ), done((&sl[2..], 0), 752));
assert_eq!(take_bits!( (sl, 6), u16, 11 ), done((&sl[2..], 1), 1504));
assert_eq!(take_bits!( (sl, 0), u32, 20 ), done((&sl[2..], 4), 700163));
assert_eq!(take_bits!( (sl, 4), u32, 20 ), done((&sl[3..], 0), 716851));
assert_eq!(take_bits!( (sl, 4), u32, 22 ), incomplete(Needed::Size(22)));
}

#[test]
fn tag_bits() {
let input = vec![0b10101010, 0b11110000, 0b00110011];
let sl = &input[..];

assert_eq!(tag_bits!( (sl, 0), u8, 3, 0b101), IResult::Done((&sl[0..], 3), 5));
assert_eq!(tag_bits!( (sl, 0), u8, 4, 0b1010), IResult::Done((&sl[0..], 4), 10));
assert_eq!(tag_bits!( (sl, 0), u8, 3, 0b101), done((&sl[0..], 3), 5));
assert_eq!(tag_bits!( (sl, 0), u8, 4, 0b1010), done((&sl[0..], 4), 10));
}

named!(ch<(&[u8],usize),(u8,u8)>,
Expand All @@ -232,16 +242,16 @@ mod tests {
fn chain_bits() {
let input = vec![0b10101010, 0b11110000, 0b00110011];
let sl = &input[..];
assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15)));
assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16)));
assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12)));
assert_eq!(ch((&input[..],0)), done((&sl[1..], 4), (5,15)));
assert_eq!(ch((&input[..],4)), done((&sl[2..], 0), (7,16)));
assert_eq!(ch((&input[..1],0)), incomplete(Needed::Size(12)));
}

named!(ch_bytes<(u8,u8)>, bits!(ch));
#[test]
fn bits_to_bytes() {
let input = vec![0b10101010, 0b11110000, 0b00110011];
assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15)));
assert_eq!(ch_bytes(&input[..]), done(&input[2..], (5,15)));
assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2)));
assert_eq!(ch_bytes(&input[1..]), IResult::Error(error_position!(ErrorKind::TagBits, &input[1..])));
}
Expand Down
24 changes: 13 additions & 11 deletions src/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ macro_rules! alt (

(__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => (
{
let res = $subrule!($i, $($args)*);
let res: $crate::IResult<_, _, _> = $subrule!($i, $($args)*);
match res {
$crate::IResult::Done(_,_) => res,
$crate::IResult::Done(_, _) => res,
$crate::IResult::Incomplete(_) => res,
_ => alt!(__impl $i, $($rest)*)
}
Expand All @@ -138,8 +138,8 @@ macro_rules! alt (
match $subrule!( $i, $($args)* ) {
$crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)),
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Error(_) => {
alt!(__impl $i, $($rest)*)
$crate::IResult::Error(_alt_err) => {
$crate::propagate_error_type(_alt_err, alt!(__impl $i, $($rest)*))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit uneasy about this. Especially, I don't know how it will interact with the whitespace parsing combinators

}
}
}
Expand All @@ -158,8 +158,8 @@ macro_rules! alt (
match $subrule!( $i, $($args)* ) {
$crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)),
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Error(_) => {
alt!(__impl $i)
$crate::IResult::Error(_alt_err) => {
$crate::propagate_error_type(_alt_err, alt!(__impl $i))
}
}
}
Expand All @@ -174,15 +174,15 @@ macro_rules! alt (
match $subrule!( $i, $($args)* ) {
$crate::IResult::Done(i,o) => $crate::IResult::Done(i,o),
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Error(_) => {
alt!(__impl $i)
$crate::IResult::Error(_alt_err) => {
$crate::propagate_error_type(_alt_err, alt!(__impl $i))
}
}
}
);

(__impl $i:expr) => (
$crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i))
$crate::IResult::Error(error_position!($crate::ErrorKind::Alt, $i))
);

($i:expr, $($rest:tt)*) => (
Expand All @@ -192,6 +192,8 @@ macro_rules! alt (
);
);



/// This is a combination of the `alt!` and `complete!` combinators. Rather
/// than returning `Incomplete` on partial input, `alt_complete!` will try the
/// next alternative in the chain. You should use this only if you know you
Expand Down Expand Up @@ -573,7 +575,7 @@ mod tests {
let reduced = &$i[..m];
let b = &$bytes[..m];

let res: $crate::IResult<_,_> = if reduced != b {
let res: $crate::IResult<_, _, u32> = if reduced != b {
$crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i))
} else if m < blen {
$crate::IResult::Incomplete($crate::Needed::Size(blen))
Expand All @@ -589,7 +591,7 @@ mod tests {
($i:expr, $count:expr) => (
{
let cnt = $count as usize;
let res:$crate::IResult<&[u8],&[u8]> = if $i.len() < cnt {
let res:$crate::IResult<&[u8], &[u8], u32> = if $i.len() < cnt {
$crate::IResult::Incomplete($crate::Needed::Size(cnt))
} else {
$crate::IResult::Done(&$i[cnt..],&$i[0..cnt])
Expand Down
53 changes: 32 additions & 21 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ macro_rules! tag (
($i:expr, $tag: expr) => (
{
use $crate::{Compare,CompareResult,InputLength,Slice};
let res: $crate::IResult<_,_> = match ($i).compare($tag) {
let res: $crate::IResult<_, _, _> = match ($i).compare($tag) {
CompareResult::Ok => {
let blen = $tag.input_len();
$crate::IResult::Done($i.slice(blen..), $i.slice(..blen))
Expand Down Expand Up @@ -58,7 +58,7 @@ macro_rules! tag_no_case (
($i:expr, $tag: expr) => (
{
use $crate::{Compare,CompareResult,InputLength,Slice};
let res: $crate::IResult<_,_> = match ($i).compare_no_case($tag) {
let res: $crate::IResult<_, _, _> = match ($i).compare_no_case($tag) {
CompareResult::Ok => {
let blen = $tag.input_len();
$crate::IResult::Done($i.slice(blen..), $i.slice(..blen))
Expand Down Expand Up @@ -98,7 +98,7 @@ macro_rules! is_not(
use $crate::FindToken;
use $crate::Slice;

let res: $crate::IResult<_,_> = match $input.position(|c| {
let res: $crate::IResult<_, _, _> = match $input.position(|c| {
c.find_token($arr)
}) {
Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::IsNot,$input)),
Expand Down Expand Up @@ -140,12 +140,12 @@ macro_rules! is_a (
use $crate::FindToken;
use $crate::Slice;

let res: $crate::IResult<_,_> = match $input.position(|c| {
let res: $crate::IResult<_, _, _> = match $input.position(|c| {
!c.find_token($arr)
}) {
Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::IsA,$input)),
Some(n) => {
let res: $crate::IResult<_,_> = $crate::IResult::Done($input.slice(n..), $input.slice(..n));
let res: $crate::IResult<_, _, _> = $crate::IResult::Done($input.slice(n..), $input.slice(..n));
res
},
None => {
Expand Down Expand Up @@ -185,7 +185,7 @@ macro_rules! escaped (
let mut index = 0;

while index < $i.input_len() {
if let $crate::IResult::Done(i,_) = $normal!($i.slice(index..), $($args)*) {
if let $crate::IResult::Done(i, _) = $normal!($i.slice(index..), $($args)*) {
if i.is_empty() {
return $crate::IResult::Done($i.slice($i.input_len()..), $i)
} else {
Expand Down Expand Up @@ -388,7 +388,7 @@ macro_rules! take_while (

match input.position(|c| !$submac!(c, $($args)*)) {
Some(n) => {
let res:$crate::IResult<_,_> = $crate::IResult::Done(input.slice(n..), input.slice(..n));
let res: $crate::IResult<_, _, _> = $crate::IResult::Done(input.slice(n..), input.slice(..n));
res
},
None => {
Expand Down Expand Up @@ -484,7 +484,7 @@ macro_rules! take (

let cnt = $count as usize;

let res: $crate::IResult<_,_> = match input.slice_index(cnt) {
let res: $crate::IResult<_, _, _> = match input.slice_index(cnt) {
None => $crate::IResult::Incomplete($crate::Needed::Size(cnt)),
//FIXME: use the InputTake trait
Some(index) => $crate::IResult::Done(input.slice(index..), input.slice(..index))
Expand Down Expand Up @@ -517,7 +517,7 @@ macro_rules! take_until_and_consume (
use $crate::FindSubstring;
use $crate::Slice;

let res: $crate::IResult<_,_> = if $substr.input_len() > $i.input_len() {
let res: $crate::IResult<_, _, _> = if $substr.input_len() > $i.input_len() {
$crate::IResult::Incomplete($crate::Needed::Size($substr.input_len()))
} else {
match ($i).find_substring($substr) {
Expand All @@ -544,7 +544,7 @@ macro_rules! take_until (
use $crate::FindSubstring;
use $crate::Slice;

let res: $crate::IResult<_,_> = if $substr.input_len() > $i.input_len() {
let res: $crate::IResult<_, _, _> = if $substr.input_len() > $i.input_len() {
$crate::IResult::Incomplete($crate::Needed::Size($substr.input_len()))
} else {
match ($i).find_substring($substr) {
Expand Down Expand Up @@ -575,7 +575,7 @@ macro_rules! take_until_either_and_consume (
if $input.input_len() == 0 {
$crate::IResult::Incomplete($crate::Needed::Size(1))
} else {
let res: $crate::IResult<_,_> = match $input.position(|c| {
let res: $crate::IResult<_, _, _> = match $input.position(|c| {
c.find_token($arr)
}) {
Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEitherAndConsume,$input)),
Expand Down Expand Up @@ -606,7 +606,7 @@ macro_rules! take_until_either (
if $input.input_len() == 0 {
$crate::IResult::Incomplete($crate::Needed::Size(1))
} else {
let res: $crate::IResult<_,_> = match $input.position(|c| {
let res: $crate::IResult<_, _, _> = match $input.position(|c| {
c.find_token($arr)
}) {
Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEither,$input)),
Expand Down Expand Up @@ -657,7 +657,7 @@ macro_rules! length_bytes(
#[cfg(test)]
mod tests {
use internal::Needed;
use internal::IResult::*;
use internal::IResult::{self, Error, Done, Incomplete};
use util::ErrorKind;
use nom::{alpha, digit, hex_digit, oct_digit, alphanumeric, space, multispace};

Expand Down Expand Up @@ -705,6 +705,16 @@ mod tests {
);
);

/// specifies type of error (as u32).
fn done<I, O>(i: I, o: O) -> IResult<I, O, u32> {
Done(i, o)
}

/// specifies type of error (as u32).
fn incomplete<I, O>(n: Needed) -> IResult<I, O, u32> {
Incomplete(n)
}

#[test]
fn is_a() {
named!(a_or_b, is_a!(&b"ab"[..]));
Expand Down Expand Up @@ -805,20 +815,21 @@ mod tests {

#[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"[..]));
named!(abcd, is_a!("abcd"));

assert_eq!(abcd(&b"aaaaefgh"[..]), Done(&b"efgh"[..], &b"aaaa"[..]));
assert_eq!(abcd(&b"aaaa"[..]), Done(&b""[..], &b"aaaa"[..]));

named!(non_zero_digit, is_a!("123456789"));
assert_eq!(non_zero_digit(&b"1"[..]), 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)));
assert_eq!(take_str!(&a[..], 5), done(&b"nom"[..], "omnom"));
assert_eq!(take_str!(&a[..], 9), incomplete(Needed::Size(9)));
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions src/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ macro_rules! char (
($i:expr, $c: expr) => (
{
if $i.is_empty() {
let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1));
let res: $crate::IResult<&[u8], char, _> = $crate::IResult::Incomplete($crate::Needed::Size(1));
res
} else {
if $i[0] == $c as u8 {
Expand All @@ -121,7 +121,7 @@ named!(#[doc="Matches a newline character '\\n'"], pub newline<char>, char!('\n'

named!(#[doc="Matches a tab character '\\t'"], pub tab<char>, char!('\t'));

pub fn anychar(input:&[u8]) -> IResult<&[u8], char> {
pub fn anychar<E>(input:&[u8]) -> IResult<&[u8], char, E> {
if input.is_empty() {
IResult::Incomplete(Needed::Size(1))
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,12 @@ mod stream;

#[cfg(not(feature = "core"))]
mod str;

/// tells rustc to use same error type for `_ignored_err` and `res`
///
/// only used for error type assertion.
#[doc(hidden)]
#[inline(always)]
pub fn propagate_error_type<I,O,E>(_ignored_err: Err<E>, res: IResult<I, O, E>) -> IResult<I, O, E> {
res
}
Loading