Solution

  1. /// An operation to perform on two subexpressions.
  2. #[derive(Debug)]
  3. enum Operation {
  4.     Add,
  5.     Sub,
  6.     Mul,
  7.     Div,
  8. }
  9. /// An expression, in tree form.
  10. #[derive(Debug)]
  11. enum Expression {
  12.     /// An operation on two subexpressions.
  13.     Op { op: Operation, left: Box<Expression>, right: Box<Expression> },
  14.     /// A literal value
  15.     Value(i64),
  16. }
  17. fn eval(e: Expression) -> Result<i64, String> {
  18.     match e {
  19.         Expression::Op { op, left, right } => {
  20.             let left = match eval(*left) {
  21.                 Ok(v) => v,
  22.                 Err(e) => return Err(e),
  23.             };
  24.             let right = match eval(*right) {
  25.                 Ok(v) => v,
  26.                 Err(e) => return Err(e),
  27.             };
  28.             Ok(match op {
  29.                 Operation::Add => left + right,
  30.                 Operation::Sub => left - right,
  31.                 Operation::Mul => left * right,
  32.                 Operation::Div => {
  33.                     if right == 0 {
  34.                         return Err(String::from("division by zero"));
  35.                     } else {
  36.                         left / right
  37.                     }
  38.                 }
  39.             })
  40.         }
  41.         Expression::Value(v) => Ok(v),
  42.     }
  43. }
  44. #[test]
  45. fn test_value() {
  46.     assert_eq!(eval(Expression::Value(19)), Ok(19));
  47. }
  48. #[test]
  49. fn test_sum() {
  50.     assert_eq!(
  51.         eval(Expression::Op {
  52.             op: Operation::Add,
  53.             left: Box::new(Expression::Value(10)),
  54.             right: Box::new(Expression::Value(20)),
  55.         }),
  56.         Ok(30)
  57.     );
  58. }
  59. #[test]
  60. fn test_recursion() {
  61.     let term1 = Expression::Op {
  62.         op: Operation::Mul,
  63.         left: Box::new(Expression::Value(10)),
  64.         right: Box::new(Expression::Value(9)),
  65.     };
  66.     let term2 = Expression::Op {
  67.         op: Operation::Mul,
  68.         left: Box::new(Expression::Op {
  69.             op: Operation::Sub,
  70.             left: Box::new(Expression::Value(3)),
  71.             right: Box::new(Expression::Value(4)),
  72.         }),
  73.         right: Box::new(Expression::Value(5)),
  74.     };
  75.     assert_eq!(
  76.         eval(Expression::Op {
  77.             op: Operation::Add,
  78.             left: Box::new(term1),
  79.             right: Box::new(term2),
  80.         }),
  81.         Ok(85)
  82.     );
  83. }
  84. #[test]
  85. fn test_zeros() {
  86.     assert_eq!(
  87.         eval(Expression::Op {
  88.             op: Operation::Add,
  89.             left: Box::new(Expression::Value(0)),
  90.             right: Box::new(Expression::Value(0))
  91.         }),
  92.         Ok(0)
  93.     );
  94.     assert_eq!(
  95.         eval(Expression::Op {
  96.             op: Operation::Mul,
  97.             left: Box::new(Expression::Value(0)),
  98.             right: Box::new(Expression::Value(0))
  99.         }),
  100.         Ok(0)
  101.     );
  102.     assert_eq!(
  103.         eval(Expression::Op {
  104.             op: Operation::Sub,
  105.             left: Box::new(Expression::Value(0)),
  106.             right: Box::new(Expression::Value(0))
  107.         }),
  108.         Ok(0)
  109.     );
  110. }
  111. #[test]
  112. fn test_error() {
  113.     assert_eq!(
  114.         eval(Expression::Op {
  115.             op: Operation::Div,
  116.             left: Box::new(Expression::Value(99)),
  117.             right: Box::new(Expression::Value(0)),
  118.         }),
  119.         Err(String::from("division by zero"))
  120.     );
  121. }
  122. fn main() {
  123.     let expr = Expression::Op {
  124.         op: Operation::Sub,
  125.         left: Box::new(Expression::Value(20)),
  126.         right: Box::new(Expression::Value(10)),
  127.     };
  128.     println!("expr: {expr:?}");
  129.     println!("result: {:?}", eval(expr));
  130. }