// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #![allow(dead_code)] // ANCHOR: types /// An operation to perform on two subexpressions. #[derive(Debug)] enum Operation { Add, Sub, Mul, Div, } /// An expression, in tree form. #[derive(Debug)] enum Expression { /// An operation on two subexpressions. Op { op: Operation, left: Box, right: Box }, /// A literal value Value(i64), } #[derive(PartialEq, Eq, Debug)] struct DivideByZeroError; // ANCHOR_END: types /* // ANCHOR: eval // The original implementation of the expression evaluator. Update this to // return a `Result` and produce an error when dividing by 0. fn eval(e: Expression) -> i64 { match e { Expression::Op { op, left, right } => { let left = eval(*left); let right = eval(*right); match op { Operation::Add => left + right, Operation::Sub => left - right, Operation::Mul => left * right, Operation::Div => if right != 0 { left / right } else { panic!("Cannot divide by zero!"); }, } } Expression::Value(v) => v, } } // ANCHOR_END: eval */ // ANCHOR: solution fn eval(e: Expression) -> Result { match e { Expression::Op { op, left, right } => { let left = eval(*left)?; let right = eval(*right)?; Ok(match op { Operation::Add => left + right, Operation::Sub => left - right, Operation::Mul => left * right, Operation::Div => { if right == 0 { return Err(DivideByZeroError); } else { left / right } } }) } Expression::Value(v) => Ok(v), } } // ANCHOR_END: solution // ANCHOR: tests #[cfg(test)] mod test { use super::*; #[test] fn test_error() { assert_eq!( eval(Expression::Op { op: Operation::Div, left: Box::new(Expression::Value(99)), right: Box::new(Expression::Value(0)), }), Err(DivideByZeroError) ); } #[test] fn test_ok() { let expr = Expression::Op { op: Operation::Sub, left: Box::new(Expression::Value(20)), right: Box::new(Expression::Value(10)), }; assert_eq!(eval(expr), Ok(10)); } } // ANCHOR_END: tests