Skip to content

Commit

Permalink
convert opt, cond and peek to functions, remove cond_reduce
Browse files Browse the repository at this point in the history
  • Loading branch information
Geal committed May 7, 2019
1 parent f19d2d8 commit abb4552
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 106 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

### Fixed

### Changed

- the verify combinator's condition function now takes its argument by reference
- `cond` will now return the error of the parser instead of None

### Removed

- character parsers that were aliases to their `*1` version: eol, alpha, digit, hex_digit, oct_digit, alphanumeric, space, multispace
Expand All @@ -27,6 +32,7 @@
- `take_until_and_consume`, `take_until_and_consume1`: they can be replaced with `take_until` combined with `take`
- `sized_buffer` and `length_bytes!`: they can be replaced with the `length_data` function
- `begin` and `rest_s` function
- `cond_reduce`

## 4.2.3 - 2019-03-23

Expand Down
111 changes: 8 additions & 103 deletions src/combinator/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,20 +958,11 @@ macro_rules! expr_opt (
macro_rules! opt(
($i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;

let i_ = $i.clone();
match $submac!(i_, $($args)*) {
Ok((i,o)) => Ok((i, Some(o))),
Err(Err::Error(_)) => Ok(($i, None)),
Err(e) => Err(e),
}
$crate::combinator::optc($i, |i| $submac!(i, $($args)*))
}
);
($i:expr, $f:expr) => (
opt!($i, call!($f));
$crate::combinator::opt($f)($i)
);
);

Expand Down Expand Up @@ -1102,88 +1093,10 @@ macro_rules! cond_with_error(
#[macro_export(local_inner_macros)]
macro_rules! cond(
($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::lib::std::option::Option::*;
use $crate::Err;

if $cond {
let i_ = $i.clone();
match $submac!(i_, $($args)*) {
Ok((i,o)) => Ok((i, Some(o))),
Err(Err::Error(_)) => {
Ok(($i, None))
},
Err(e) => Err(e),
}
} else {
Ok(($i, None))
}
}
$crate::combinator::condc($i, $cond, |i| $submac!(i, $($args)*) )
);
($i:expr, $cond:expr, $f:expr) => (
cond!($i, $cond, call!($f));
);
);

//FIXME: error rewrite
/// `cond_reduce!(bool, I -> IResult<I,O>) => I -> IResult<I, O>`
/// Conditional combinator with error
///
/// Wraps another parser and calls it if the
/// condition is met. This combinator returns
/// an error if the condition is false
///
/// This is especially useful if a parser depends
/// on the value returned by a preceding parser in
/// a `do_parse!`.
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::ErrorKind,IResult};
/// # fn main() {
/// /*
/// let b = true;
/// let f = closure!(&'static[u8],
/// cond_reduce!( b, tag!("abcd") )
/// );
///
/// let a = b"abcdef";
/// assert_eq!(f(&a[..]), Ok((&b"ef"[..], &b"abcd"[..])));
///
/// let b2 = false;
/// let f2 = closure!(&'static[u8],
/// cond_reduce!( b2, tag!("abcd") )
/// );
/// assert_eq!(f2(&a[..]), Err(Err::Error(error_position!(&a[..], ErrorKind::CondReduce))));
/// */
/// # }
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! cond_reduce(
($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::{Err,error::ErrorKind,IResult};
let default_err = Err(Err::convert(Err::Error(error_position!($i, ErrorKind::CondReduce))));

if $cond {
let sub_res = $submac!($i, $($args)*);
fn unify_types<I,O,E>(_: &IResult<I,O,E>, _: &IResult<I,O,E>) {}
unify_types(&sub_res, &default_err);

match sub_res {
Ok((i,o)) => Ok((i, o)),
Err(e) => Err(e),
}
} else {
default_err
}
}
);
($i:expr, $cond:expr, $f:expr) => (
cond_reduce!($i, $cond, call!($f));
$crate::combinator::cond($cond, $f)($i)
);
);

Expand All @@ -1204,19 +1117,11 @@ macro_rules! cond_reduce(
#[macro_export(local_inner_macros)]
macro_rules! peek(
($i:expr, $submac:ident!( $($args:tt)* )) => (
{
use $crate::lib::std::result::Result::*;
use $crate::Err;

let i_ = $i.clone();
match $submac!(i_, $($args)*) {
Ok((_,o)) => Ok(($i, o)),
Err(e) => Err(Err::convert(e)),
}
}
$crate::combinator::peekc($i, |i| $submac!(i, $($args)*))
);
($i:expr, $f:expr) => (
peek!($i, call!($f));
$crate::combinator::peek($f)($i)
);
);

Expand Down Expand Up @@ -1527,7 +1432,7 @@ mod tests {

assert_eq!(f_true(&b"abcdef"[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
assert_eq!(f_true(&b"ab"[..]), Err(Err::Incomplete(Needed::Size(4))));
assert_eq!(f_true(&b"xxx"[..]), Ok((&b"xxx"[..], None)));
assert_eq!(f_true(&b"xxx"[..]), Err(Err::Error(CustomError("test"))));

assert_eq!(f_false(&b"abcdef"[..]), Ok((&b"abcdef"[..], None)));
assert_eq!(f_false(&b"ab"[..]), Ok((&b"ab"[..], None)));
Expand All @@ -1551,7 +1456,7 @@ mod tests {

assert_eq!(f_true(&b"abcdef"[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
assert_eq!(f_true(&b"ab"[..]), Err(Err::Incomplete(Needed::Size(4))));
assert_eq!(f_true(&b"xxx"[..]), Ok((&b"xxx"[..], None)));
assert_eq!(f_true(&b"xxx"[..]), Err(Err::Error(CustomError("test"))));

assert_eq!(f_false(&b"abcdef"[..]), Ok((&b"abcdef"[..], None)));
assert_eq!(f_false(&b"ab"[..]), Ok((&b"ab"[..], None)));
Expand Down
55 changes: 55 additions & 0 deletions src/combinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,61 @@ where
}
}

#[doc(hidden)]
pub fn optc<I:Clone, O, E: ParseError<I>, F>(input: I, f: F) -> IResult<I, Option<O>, E>
where
F: Fn(I) -> IResult<I, O, E>,
{
opt(f)(input)
}

/// call the parser if the condition is met
pub fn cond<I:Clone, O, E: ParseError<I>, F>(b: bool, f: F) -> impl Fn(I) -> IResult<I, Option<O>, E>
where
F: Fn(I) -> IResult<I, O, E>,
{
move |input: I| {
if b {
match f(input) {
Ok((i, o)) => Ok((i, Some(o))),
Err(e) => Err(e),
}
} else {
Ok((input, None))
}
}
}

#[doc(hidden)]
pub fn condc<I:Clone, O, E: ParseError<I>, F>(input: I, b: bool, f: F) -> IResult<I, Option<O>, E>
where
F: Fn(I) -> IResult<I, O, E>,
{
cond(b, f)(input)
}

/// optional parser: will return None if not successful
pub fn peek<I:Clone, O, E: ParseError<I>, F>(f: F) -> impl Fn(I) -> IResult<I, O, E>
where
F: Fn(I) -> IResult<I, O, E>,
{
move |input: I| {
let i = input.clone();
match f(input) {
Ok((_, o)) => Ok((i, o)),
Err(e) => Err(e),
}
}
}

#[doc(hidden)]
pub fn peekc<I:Clone, O, E: ParseError<I>, F>(input: I, f: F) -> IResult<I, O, E>
where
F: Fn(I) -> IResult<I, O, E>,
{
peek(f)(input)
}

/// transforms Incomplete into Error
pub fn complete<I: Clone, O, E: ParseError<I>, F>(f: F) -> impl Fn(I) -> IResult<I, O, E>
where
Expand Down
3 changes: 0 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ pub enum ErrorKind {
Eof,
ExprOpt,
ExprRes,
CondReduce,
Switch,
TagBits,
OneOf,
Expand Down Expand Up @@ -202,7 +201,6 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 {
ErrorKind::Eof => 23,
ErrorKind::ExprOpt => 24,
ErrorKind::ExprRes => 25,
ErrorKind::CondReduce => 26,
ErrorKind::Switch => 27,
ErrorKind::TagBits => 28,
ErrorKind::OneOf => 29,
Expand Down Expand Up @@ -267,7 +265,6 @@ impl ErrorKind {
ErrorKind::Eof => "End of file",
ErrorKind::ExprOpt => "Evaluate Option",
ErrorKind::ExprRes => "Evaluate Result",
ErrorKind::CondReduce => "Condition reduce",
ErrorKind::Switch => "Switch",
ErrorKind::TagBits => "Tag on bitstream",
ErrorKind::OneOf => "OneOf",
Expand Down

0 comments on commit abb4552

Please sign in to comment.