1 use std::fmt;
2 use std::fmt::{Debug, Display, Formatter};
3
4 use std::str::FromStr;
5
6 use nom::{
7 branch::alt,
8 bytes::complete::tag,
9 character::complete::{digit1 as digit, multispace0 as multispace},
10 combinator::{map, map_res},
11 multi::many0,
12 sequence::{delimited, preceded},
13 IResult,
14 };
15
16 pub enum Expr {
17 Value(i64),
18 Add(Box<Expr>, Box<Expr>),
19 Sub(Box<Expr>, Box<Expr>),
20 Mul(Box<Expr>, Box<Expr>),
21 Div(Box<Expr>, Box<Expr>),
22 Paren(Box<Expr>),
23 }
24
25 #[derive(Debug)]
26 pub enum Oper {
27 Add,
28 Sub,
29 Mul,
30 Div,
31 }
32
33 impl Display for Expr {
fmt(&self, format: &mut Formatter<'_>) -> fmt::Result34 fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
35 use self::Expr::*;
36 match *self {
37 Value(val) => write!(format, "{}", val),
38 Add(ref left, ref right) => write!(format, "{} + {}", left, right),
39 Sub(ref left, ref right) => write!(format, "{} - {}", left, right),
40 Mul(ref left, ref right) => write!(format, "{} * {}", left, right),
41 Div(ref left, ref right) => write!(format, "{} / {}", left, right),
42 Paren(ref expr) => write!(format, "({})", expr),
43 }
44 }
45 }
46
47 impl Debug for Expr {
fmt(&self, format: &mut Formatter<'_>) -> fmt::Result48 fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
49 use self::Expr::*;
50 match *self {
51 Value(val) => write!(format, "{}", val),
52 Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right),
53 Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right),
54 Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right),
55 Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right),
56 Paren(ref expr) => write!(format, "[{:?}]", expr),
57 }
58 }
59 }
60
parens(i: &str) -> IResult<&str, Expr>61 fn parens(i: &str) -> IResult<&str, Expr> {
62 delimited(
63 multispace,
64 delimited(tag("("), map(expr, |e| Expr::Paren(Box::new(e))), tag(")")),
65 multispace,
66 )(i)
67 }
68
factor(i: &str) -> IResult<&str, Expr>69 fn factor(i: &str) -> IResult<&str, Expr> {
70 alt((
71 map(
72 map_res(delimited(multispace, digit, multispace), FromStr::from_str),
73 Expr::Value,
74 ),
75 parens,
76 ))(i)
77 }
78
fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr79 fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr {
80 remainder.into_iter().fold(initial, |acc, pair| {
81 let (oper, expr) = pair;
82 match oper {
83 Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)),
84 Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)),
85 Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)),
86 Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)),
87 }
88 })
89 }
90
term(i: &str) -> IResult<&str, Expr>91 fn term(i: &str) -> IResult<&str, Expr> {
92 let (i, initial) = factor(i)?;
93 let (i, remainder) = many0(alt((
94 |i| {
95 let (i, mul) = preceded(tag("*"), factor)(i)?;
96 Ok((i, (Oper::Mul, mul)))
97 },
98 |i| {
99 let (i, div) = preceded(tag("/"), factor)(i)?;
100 Ok((i, (Oper::Div, div)))
101 },
102 )))(i)?;
103
104 Ok((i, fold_exprs(initial, remainder)))
105 }
106
expr(i: &str) -> IResult<&str, Expr>107 fn expr(i: &str) -> IResult<&str, Expr> {
108 let (i, initial) = term(i)?;
109 let (i, remainder) = many0(alt((
110 |i| {
111 let (i, add) = preceded(tag("+"), term)(i)?;
112 Ok((i, (Oper::Add, add)))
113 },
114 |i| {
115 let (i, sub) = preceded(tag("-"), term)(i)?;
116 Ok((i, (Oper::Sub, sub)))
117 },
118 )))(i)?;
119
120 Ok((i, fold_exprs(initial, remainder)))
121 }
122
123 #[test]
factor_test()124 fn factor_test() {
125 assert_eq!(
126 factor(" 3 ").map(|(i, x)| (i, format!("{:?}", x))),
127 Ok(("", String::from("3")))
128 );
129 }
130
131 #[test]
term_test()132 fn term_test() {
133 assert_eq!(
134 term(" 3 * 5 ").map(|(i, x)| (i, format!("{:?}", x))),
135 Ok(("", String::from("(3 * 5)")))
136 );
137 }
138
139 #[test]
expr_test()140 fn expr_test() {
141 assert_eq!(
142 expr(" 1 + 2 * 3 ").map(|(i, x)| (i, format!("{:?}", x))),
143 Ok(("", String::from("(1 + (2 * 3))")))
144 );
145 assert_eq!(
146 expr(" 1 + 2 * 3 / 4 - 5 ").map(|(i, x)| (i, format!("{:?}", x))),
147 Ok(("", String::from("((1 + ((2 * 3) / 4)) - 5)")))
148 );
149 assert_eq!(
150 expr(" 72 / 2 / 3 ").map(|(i, x)| (i, format!("{:?}", x))),
151 Ok(("", String::from("((72 / 2) / 3)")))
152 );
153 }
154
155 #[test]
parens_test()156 fn parens_test() {
157 assert_eq!(
158 expr(" ( 1 + 2 ) * 3 ").map(|(i, x)| (i, format!("{:?}", x))),
159 Ok(("", String::from("([(1 + 2)] * 3)")))
160 );
161 }
162