Skip to content

Suggestion: fold_while support for (fold_many0 / fold_many1)? #1289

@tyrchen

Description

@tyrchen

First of all, thanks for providing such a great tool for building parsers.

When I built an expression evaluator, I'd like to do certain optimization, for example:

(expr1 or expr2 or expr3) and expr4

if expr1 is true, I'd skip the evaluation of expr2 and expr4, thus the whole sub expr inside brackets would be true.

I'm using fold_many0 for it, but if there's something like fold_many0_while like below, it would be great:

use nom::IResult;

pub enum FoldWhile<T> {
    Continue(T),
    Done(T),
}

// copied and modified from https://docs.rs/nom/6.1.2/src/nom/multi/mod.rs.html#723-760
pub fn fold_many0_while<I, O, E, F, G, R>(
    mut f: F,
    init: R,
    mut g: G,
) -> impl FnMut(I) -> IResult<I, R, E>
where
    I: Clone + PartialEq,
    F: nom::Parser<I, O, E>,
    G: FnMut(R, O) -> FoldWhile<R>,
    E: nom::error::ParseError<I>,
    R: Clone,
{
    use nom::error::ErrorKind;
    use nom::Err;
    move |i: I| {
        let mut res = init.clone();
        let mut input = i;

        loop {
            let i_ = input.clone();
            match f.parse(i_) {
                Ok((i, o)) => {
                    // loop trip must always consume (otherwise infinite loops)
                    if i == input {
                        return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0)));
                    }

                    res = match g(res, o) {
                        FoldWhile::Continue(v) => v,
                        FoldWhile::Done(v) => return Ok((i, v)),
                    };
                    input = i;
                }
                Err(Err::Error(_)) => {
                    return Ok((input, res));
                }
                Err(e) => {
                    return Err(e);
                }
            }
        }
    }
}

Is there any plan for such features? I'd love to make a PR if this is the direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions