From b3866eea9e0c54468a9232bf5e008e9e7ae5a0e0 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sun, 30 May 2021 13:26:10 -0500 Subject: [PATCH] Fix panic on arithmetic error Divide by zero and add, subtract, or multiply with overflow are all caught now and reported as an ArithmeticError, rather than causing the interpreter to panic. --- src/interpret.rs | 49 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/interpret.rs b/src/interpret.rs index 4f3dc4a6..caf4b3af 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -110,21 +110,42 @@ impl ExecEnv { use Expr::*; use Value::*; - // NOTE(Alex): This is quite nasty, and should probably be - // re-done using macros or something. + // NOTE(Alex): This is really quite horrible. I think the only + // real way to clean it up would be to re-engineer the AST's + // representation to be more hierarchical: rather than having + // e.g. "Expr::Add" and "Expr::Subtract" each with a "left" + // and "right" struct member, have something like + // "Expr::Binary { oper: BinOp, left: Box, right: + // Box }". That way we could factor out a whole bunch of + // common code here. + // + // That work should probably wait for Ondra's new parser to + // come in, however. Ok(match expr { - Add { left, right } => { - Int(i32::try_from(self.eval_expr(left)?)? + i32::try_from(self.eval_expr(right)?)?) - } - Subtract { left, right } => { - Int(i32::try_from(self.eval_expr(left)?)? - i32::try_from(self.eval_expr(right)?)?) - } - Multiply { left, right } => { - Int(i32::try_from(self.eval_expr(left)?)? * i32::try_from(self.eval_expr(right)?)?) - } - Divide { left, right } => { - Int(i32::try_from(self.eval_expr(left)?)? / i32::try_from(self.eval_expr(right)?)?) - } + Add { left, right } => Int(i32::try_from(self.eval_expr(left)?)? + .checked_add(i32::try_from(self.eval_expr(right)?)?) + .ok_or(Error { + kind: ErrorKind::ArithmeticError, + position: 0..0, + })?), + Subtract { left, right } => Int(i32::try_from(self.eval_expr(left)?)? + .checked_sub(i32::try_from(self.eval_expr(right)?)?) + .ok_or(Error { + kind: ErrorKind::ArithmeticError, + position: 0..0, + })?), + Multiply { left, right } => Int(i32::try_from(self.eval_expr(left)?)? + .checked_mul(i32::try_from(self.eval_expr(right)?)?) + .ok_or(Error { + kind: ErrorKind::ArithmeticError, + position: 0..0, + })?), + Divide { left, right } => Int(i32::try_from(self.eval_expr(left)?)? + .checked_div(i32::try_from(self.eval_expr(right)?)?) + .ok_or(Error { + kind: ErrorKind::ArithmeticError, + position: 0..0, + })?), Lt { left, right } => { Bool(i32::try_from(self.eval_expr(left)?)? < i32::try_from(self.eval_expr(right)?)?) }