1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
use std::str::FromStr;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{digit1 as digits, multispace0 as multispaces},
combinator::alt,
combinator::delimited,
combinator::repeat,
token::one_of,
};
// Parser definition
pub(crate) fn expr(i: &mut &str) -> Result<i64> {
let init = term.parse_next(i)?;
repeat(0.., (one_of(['+', '-']), term))
.fold(
move || init,
|acc, (op, val): (char, i64)| {
if op == '+' {
acc + val
} else {
acc - val
}
},
)
.parse_next(i)
}
// We read an initial factor and for each time we find
// a * or / operator followed by another factor, we do
// the math by folding everything
pub(crate) fn term(i: &mut &str) -> Result<i64> {
let init = factor.parse_next(i)?;
repeat(0.., (one_of(['*', '/']), factor))
.fold(
move || init,
|acc, (op, val): (char, i64)| {
if op == '*' {
acc * val
} else {
acc / val
}
},
)
.parse_next(i)
}
// We transform an integer string into a i64, ignoring surrounding whitespace
// We look for a digit suite, and try to convert it.
// If either str::from_utf8 or FromStr::from_str fail,
// we fallback to the parens parser defined above
pub(crate) fn factor(i: &mut &str) -> Result<i64> {
delimited(
multispaces,
alt((digits.try_map(FromStr::from_str), parens)),
multispaces,
)
.parse_next(i)
}
// We parse any expr surrounded by parens, ignoring all whitespace around those
fn parens(i: &mut &str) -> Result<i64> {
delimited('(', expr, ')').parse_next(i)
}
|