mod parser { use pest_derive::Parser; #[derive(Parser)] #[grammar = "../examples/calc.pest"] pub struct Parser; } use parser::Rule; use pest::{ iterators::Pairs, pratt_parser::{Assoc::*, Op, PrattParser}, Parser, }; use std::io::{stdin, stdout, Write}; fn parse_to_str(pairs: Pairs, pratt: &PrattParser) -> String { pratt .map_primary(|primary| match primary.as_rule() { Rule::int => primary.as_str().to_owned(), Rule::expr => parse_to_str(primary.into_inner(), pratt), _ => unreachable!(), }) .map_prefix(|op, rhs| match op.as_rule() { Rule::neg => format!("(-{})", rhs), _ => unreachable!(), }) .map_postfix(|lhs, op| match op.as_rule() { Rule::fac => format!("({}!)", lhs), _ => unreachable!(), }) .map_infix(|lhs, op, rhs| match op.as_rule() { Rule::add => format!("({}+{})", lhs, rhs), Rule::sub => format!("({}-{})", lhs, rhs), Rule::mul => format!("({}*{})", lhs, rhs), Rule::div => format!("({}/{})", lhs, rhs), Rule::pow => format!("({}^{})", lhs, rhs), _ => unreachable!(), }) .parse(pairs) } fn parse_to_i32(pairs: Pairs, pratt: &PrattParser) -> i128 { pratt .map_primary(|primary| match primary.as_rule() { Rule::int => primary.as_str().parse().unwrap(), Rule::expr => parse_to_i32(primary.into_inner(), pratt), _ => unreachable!(), }) .map_prefix(|op, rhs| match op.as_rule() { Rule::neg => -rhs, _ => unreachable!(), }) .map_postfix(|lhs, op| match op.as_rule() { Rule::fac => (1..lhs + 1).product(), _ => unreachable!(), }) .map_infix(|lhs, op, rhs| match op.as_rule() { Rule::add => lhs + rhs, Rule::sub => lhs - rhs, Rule::mul => lhs * rhs, Rule::div => lhs / rhs, Rule::pow => (1..rhs + 1).map(|_| lhs).product(), _ => unreachable!(), }) .parse(pairs) } fn main() { let pratt = PrattParser::new() .op(Op::infix(Rule::add, Left) | Op::infix(Rule::sub, Left)) .op(Op::infix(Rule::mul, Left) | Op::infix(Rule::div, Left)) .op(Op::infix(Rule::pow, Right)) .op(Op::postfix(Rule::fac)) .op(Op::prefix(Rule::neg)); let stdin = stdin(); let mut stdout = stdout(); loop { let source = { print!("> "); let _ = stdout.flush(); let mut input = String::new(); let _ = stdin.read_line(&mut input); input.trim().to_string() }; let pairs = match parser::Parser::parse(Rule::program, &source) { Ok(mut parse_tree) => { parse_tree .next() .unwrap() .into_inner() // inner of program .next() .unwrap() .into_inner() // inner of expr } Err(err) => { println!("Failed parsing input: {:}", err); continue; } }; print!("{} => ", source); print!("{} => ", parse_to_str(pairs.clone(), &pratt)); println!("{}", parse_to_i32(pairs.clone(), &pratt)); } }