1extern crate fuel_pest as pest;
2
3use std::{
4 io::{self, Write},
5 sync::Arc,
6};
7
8use pest::error::Error;
9use pest::iterators::Pairs;
10use pest::{state, ParseResult, Parser, ParserState};
11
12#[allow(dead_code, non_camel_case_types)]
13#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
14enum Rule {
15 expr,
16 paren,
17 paren_end,
18}
19
20struct ParenParser;
21
22impl Parser<Rule> for ParenParser {
23 fn parse(rule: Rule, input: Arc<str>) -> Result<Pairs<Rule>, Error<Rule>> {
24 fn expr(state: Box<ParserState<Rule>>) -> ParseResult<Box<ParserState<Rule>>> {
25 state.sequence(|s| s.repeat(|s| paren(s)).and_then(|s| s.end_of_input()))
26 }
27
28 fn paren(state: Box<ParserState<Rule>>) -> ParseResult<Box<ParserState<Rule>>> {
29 state.rule(Rule::paren, |s| {
30 s.sequence(|s| {
31 s.match_string("(")
32 .and_then(|s| {
33 s.optional(|s| {
34 s.sequence(|s| {
35 s.lookahead(true, |s| s.match_string("("))
36 .and_then(|s| s.repeat(|s| paren(s)))
37 })
38 })
39 })
40 .and_then(|s| s.rule(Rule::paren_end, |s| s.match_string(")")))
41 })
42 })
43 }
44
45 state(input, |state| match rule {
46 Rule::expr => expr(state),
47 Rule::paren => paren(state),
48 _ => unreachable!(),
49 })
50 }
51}
52
53#[derive(Debug)]
54struct Paren(Vec<Paren>);
55
56fn expr(pairs: Pairs<Rule>) -> Vec<Paren> {
57 pairs
58 .filter(|p| p.as_rule() == Rule::paren)
59 .map(|p| Paren(expr(p.into_inner())))
60 .collect()
61}
62
63fn main() {
64 loop {
65 let mut line = String::new();
66
67 print!("> ");
68 io::stdout().flush().unwrap();
69
70 io::stdin().read_line(&mut line).unwrap();
71 line.pop();
72
73 match ParenParser::parse(Rule::expr, Arc::from(line)) {
74 Ok(pairs) => println!("{:?}", expr(pairs)),
75 Err(e) => println!("\n{}", e),
76 };
77 }
78}