1 #[macro_use]
2 extern crate nom;
3 
4 use std::fmt;
5 use std::fmt::{Display, Debug, Formatter};
6 
7 use std::str;
8 use std::str::FromStr;
9 
10 use nom::{IResult, digit, multispace};
11 
12 pub enum Expr {
13     Value(i64),
14     Add(Box<Expr>, Box<Expr>),
15     Sub(Box<Expr>, Box<Expr>),
16     Mul(Box<Expr>, Box<Expr>),
17     Div(Box<Expr>, Box<Expr>),
18     Paren(Box<Expr>),
19 }
20 
21 pub enum Oper {
22     Add,
23     Sub,
24     Mul,
25     Div,
26 }
27 
28 impl Display for Expr {
fmt(&self, format: &mut Formatter) -> fmt::Result29     fn fmt(&self, format: &mut Formatter) -> fmt::Result {
30         use self::Expr::*;
31         match *self {
32             Value(val) => write!(format, "{}", val),
33             Add(ref left, ref right) => write!(format, "{} + {}", left, right),
34             Sub(ref left, ref right) => write!(format, "{} - {}", left, right),
35             Mul(ref left, ref right) => write!(format, "{} * {}", left, right),
36             Div(ref left, ref right) => write!(format, "{} / {}", left, right),
37             Paren(ref expr) => write!(format, "({})", expr),
38         }
39     }
40 }
41 
42 impl Debug for Expr {
fmt(&self, format: &mut Formatter) -> fmt::Result43     fn fmt(&self, format: &mut Formatter) -> fmt::Result {
44         use self::Expr::*;
45         match *self {
46             Value(val) => write!(format, "{}", val),
47             Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right),
48             Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right),
49             Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right),
50             Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right),
51             Paren(ref expr) => write!(format, "[{:?}]", expr),
52         }
53     }
54 }
55 
56 named!(parens< Expr >, delimited!(
57     delimited!(opt!(multispace), tag!("("), opt!(multispace)),
58     map!(map!(expr, Box::new), Expr::Paren),
59     delimited!(opt!(multispace), tag!(")"), opt!(multispace))
60   )
61 );
62 
63 named!(factor< Expr >, alt_complete!(
64     map!(
65       map_res!(
66         map_res!(
67           delimited!(opt!(multispace), digit, opt!(multispace)),
68           str::from_utf8
69         ),
70       FromStr::from_str
71     ),
72     Expr::Value)
73   | parens
74   )
75 );
76 
fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr77 fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr {
78     remainder.into_iter().fold(initial, |acc, pair| {
79         let (oper, expr) = pair;
80         match oper {
81             Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)),
82             Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)),
83             Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)),
84             Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)),
85         }
86     })
87 }
88 
89 named!(term< Expr >, chain!(
90     initial: factor ~
91     remainder: many0!(
92            alt!(
93              chain!(tag!("*") ~ mul: factor, || { (Oper::Mul, mul) }) |
94              chain!(tag!("/") ~ div: factor, || { (Oper::Div, div) })
95            )
96          ),
97     || fold_exprs(initial, remainder))
98 );
99 
100 named!(expr< Expr >, chain!(
101     initial: term ~
102     remainder: many0!(
103            alt!(
104              chain!(tag!("+") ~ add: term, || { (Oper::Add, add) }) |
105              chain!(tag!("-") ~ sub: term, || { (Oper::Sub, sub) })
106            )
107          ),
108     || fold_exprs(initial, remainder))
109 );
110 
111 #[test]
factor_test()112 fn factor_test() {
113     assert_eq!(factor(&b"  3  "[..]).map(|x| format!("{:?}", x)),
114                IResult::Done(&b""[..], String::from("3")));
115 }
116 
117 #[test]
term_test()118 fn term_test() {
119     assert_eq!(term(&b" 3 *  5   "[..]).map(|x| format!("{:?}", x)),
120                IResult::Done(&b""[..], String::from("(3 * 5)")));
121 }
122 
123 #[test]
expr_test()124 fn expr_test() {
125     assert_eq!(expr(&b" 1 + 2 *  3 "[..]).map(|x| format!("{:?}", x)),
126                IResult::Done(&b""[..], String::from("(1 + (2 * 3))")));
127     assert_eq!(expr(&b" 1 + 2 *  3 / 4 - 5 "[..]).map(|x| format!("{:?}", x)),
128                IResult::Done(&b""[..], String::from("((1 + ((2 * 3) / 4)) - 5)")));
129     assert_eq!(expr(&b" 72 / 2 / 3 "[..]).map(|x| format!("{:?}", x)),
130                IResult::Done(&b""[..], String::from("((72 / 2) / 3)")));
131 }
132 
133 #[test]
parens_test()134 fn parens_test() {
135     assert_eq!(expr(&b" ( 1 + 2 ) *  3 "[..]).map(|x| format!("{:?}", x)),
136                IResult::Done(&b""[..], String::from("([(1 + 2)] * 3)")));
137 }
138