extern crate pest; use std::io::{self, Write}; use pest::error::Error; use pest::iterators::Pairs; use pest::{state, ParseResult, Parser, ParserState}; #[allow(dead_code, non_camel_case_types)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] enum Rule { expr, paren, paren_end, } struct ParenParser; impl Parser for ParenParser { fn parse(rule: Rule, input: &str) -> Result, Error> { fn expr(state: Box>) -> ParseResult>> { state.sequence(|s| s.repeat(|s| paren(s)).and_then(|s| s.end_of_input())) } fn paren(state: Box>) -> ParseResult>> { state.rule(Rule::paren, |s| { s.sequence(|s| { s.match_string("(") .and_then(|s| { s.optional(|s| { s.sequence(|s| { s.lookahead(true, |s| s.match_string("(")) .and_then(|s| s.repeat(|s| paren(s))) }) }) }) .and_then(|s| s.rule(Rule::paren_end, |s| s.match_string(")"))) }) }) } state(input, |state| match rule { Rule::expr => expr(state), Rule::paren => paren(state), _ => unreachable!(), }) } } #[derive(Debug)] struct Paren(Vec); fn expr(pairs: Pairs) -> Vec { pairs .filter(|p| p.as_rule() == Rule::paren) .map(|p| Paren(expr(p.into_inner()))) .collect() } fn main() { loop { let mut line = String::new(); print!("> "); io::stdout().flush().unwrap(); io::stdin().read_line(&mut line).unwrap(); line.pop(); match ParenParser::parse(Rule::expr, &line) { Ok(pairs) => println!("{:?}", expr(pairs)), Err(e) => println!("\n{}", e), }; } }