blob: 61df2527c2e563c71c6322d3eac27eec5d3a57ef [file] [log] [blame]
mod parser {
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "../examples/base.pest"]
#[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<Rule>, pratt: &PrattParser<Rule>) -> 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<Rule>, pratt: &PrattParser<Rule>) -> 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::prefix(Rule::neg))
.op(Op::postfix(Rule::fac));
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));
}
}