• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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