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>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));