use crate::{InputToken, Parser};
pub fn chain_left<P, IT, O, OP, F>(operand_parser: &P, operator_parser: &OP) -> impl Parser<IT, O>
where
P: Parser<IT, O>,
IT: InputToken,
OP: Parser<IT, F>,
F: Fn(O, O) -> O,
{
move |input| {
let mut operand1 = operand_parser(input)?;
while let Ok(operator) = operator_parser(input) {
let operand2 = operand_parser(input)?;
operand1 = operator(operand1, operand2);
}
Ok(operand1)
}
}
pub fn chain_right<P, IT, O, OP, F>(operand_parser: &P, operator_parser: &OP) -> impl Parser<IT, O>
where
P: Parser<IT, O>,
IT: InputToken,
OP: Parser<IT, F>,
F: Fn(O, O) -> O,
{
move |input| {
let operand1 = operand_parser(input)?;
match operator_parser(input) {
Ok(operator) => {
let operand2 = chain_right(operand_parser, operator_parser)(input)?;
let output = operator(operand1, operand2);
Ok(output)
}
Err(_) => Ok(operand1),
}
}
}
#[cfg(test)]
mod tests {
mod chain_left {
use crate::input::CharToken;
use crate::*;
fn parse_evaluate_left_subtraction() -> impl Parser<CharToken, i32> {
|input| {
let operand = satisfy(|c: &char| c.to_digit(10).map(|x| x as i32));
let operator = satisfy(|c: &char| match c {
'-' => Some(|a, b| a - b),
_ => None,
});
chain_left(&operand, &operator)(input)
}
}
#[test]
fn empty() {
let mut input = Input::new_from_chars("".chars(), None);
let output = parse_evaluate_left_subtraction()(&mut input);
assert_eq!(output, Err(Error::EndOfInput(None)));
}
#[test]
fn one_operand() {
let mut input = Input::new_from_chars("1".chars(), None);
let output = parse_evaluate_left_subtraction()(&mut input);
assert_eq!(output, Ok(1));
}
#[test]
fn two_operands() {
let mut input = Input::new_from_chars("9-7".chars(), None);
let output = parse_evaluate_left_subtraction()(&mut input);
assert_eq!(output, Ok(2));
}
#[test]
fn tree_operands() {
let mut input = Input::new_from_chars("3-1-2".chars(), None);
let output = parse_evaluate_left_subtraction()(&mut input);
assert_eq!(output, Ok(0));
}
}
mod chain_right {
use crate::input::CharToken;
use crate::*;
fn parse_evaluate_right_subtraction() -> impl Parser<CharToken, i32> {
|input| {
let operand = satisfy(|c: &char| c.to_digit(10).map(|x| x as i32));
let operator = satisfy(|c: &char| match c {
'-' => Some(|a, b| a - b),
_ => None,
});
chain_right(&operand, &operator)(input)
}
}
#[test]
fn empty() {
let mut input = Input::new_from_chars("".chars(), None);
let output = parse_evaluate_right_subtraction()(&mut input);
assert_eq!(output, Err(Error::EndOfInput(None)));
}
#[test]
fn one_operand() {
let mut input = Input::new_from_chars("1".chars(), None);
let output = parse_evaluate_right_subtraction()(&mut input);
assert_eq!(output, Ok(1));
}
#[test]
fn two_operands() {
let mut input = Input::new_from_chars("9-7".chars(), None);
let output = parse_evaluate_right_subtraction()(&mut input);
assert_eq!(output, Ok(2));
}
#[test]
fn tree_operands() {
let mut input = Input::new_from_chars("3-1-2".chars(), None);
let output = parse_evaluate_right_subtraction()(&mut input);
assert_eq!(output, Ok(4));
}
}
}