expression

Function expression 

Source
pub fn expression<I, ParseOperand, O, E>(
    parse_operand: ParseOperand,
) -> Expression<I, O, ParseOperand, impl Parser<I, Prefix<I, O, E>, E>, impl Parser<I, Postfix<I, O, E>, E>, impl Parser<I, Infix<I, O, E>, E>, E>
where I: Stream + StreamIsPartial, ParseOperand: Parser<I, O, E>, E: ParserError<I>,
Expand description

Parses an expression based on operator precedence.

It uses a Pratt parsing algorithm, where operators are associated with a binding power. The higher the power, the more tightly an operator will bind to its operands.

This method returns an Expression, which configures the Pratt parser.

Each operator type is configured with Prefix, Postfix, and Infix. These describe the operator’s binding power, a function that applies the operator to its operand, and the operator’s associativity (infix only).

For a more full-featured example, look at the [C-style Expression][crate::_topic::arithmetic#c-style-expression] topic.

§Example

Parsing a simple arithmetic expression without parenthesis.

use winnow::combinator::expression;
use winnow::combinator::{Prefix, Postfix, Infix};

fn parser<'i>() -> impl Parser<&'i str, i32, ContextError> {
    move |i: &mut &str| {
        use Infix::*;
        expression(digit1.parse_to::<i32>()) // operands are 32-bit integers
            .prefix(dispatch! {any;
                '-' => Prefix(12, |_, a: i32| Ok(-a)),
                _ => fail,
            })
            .infix(dispatch! {any;
                '+' => Left(5, |_, a, b| Ok(a + b)),
                '-' => Left(5, |_, a, b| Ok(a - b)),
                '*' => Left(7, |_, a, b| Ok(a * b)),
                '/' => Left(7, |_, a: i32, b| Ok(a.checked_div(b).unwrap_or_default())),
                _ => fail,
            })
            .postfix(dispatch! {any;
                '!' => Postfix(15, |_, a| if a < 1 { Ok(1) } else { Ok((1..=a).fold(1, |acc, a| acc*a)) }),
                _ => fail,
            })
            .parse_next(i)
    }
}

assert_eq!(parser().parse("1+1"), Ok(2));
assert_eq!(parser().parse("0!"), Ok(1));
assert_eq!(parser().parse("-1*5*2*10+30/3!"), Ok(-95));