diff --git a/src/interpreter.rs b/src/interpreter.rs index 36d5f68..ebbe535 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -48,146 +48,145 @@ impl Interpreter { #[tracing::instrument(name = "expr", skip_all)] fn interpret_expr(&self, expr: &Spanned) -> Result { match expr.as_ref() { - Expr::Binary { left, op, right } => { - let span = info_span!("binary"); - let _guard = span.enter(); - - tracing::trace!("evaluating lhs of binary expr"); - let left_val = self.interpret_expr(left)?; - - tracing::trace!("evaluating rhs of binary expr"); - let right_val = self.interpret_expr(right)?; - - match op.as_ref() { - BinaryOp::Add => match (&left_val, &right_val) { - (Value::String(left_str), Value::String(right_str)) => { - let mut s = left_str.clone(); - s.push_str(right_str); - Ok(Value::String(s)) - } - (Value::String(_), _) => Err(RuntimeError::non_string_concat( - &right_val, - right.span(), - op.span(), - )), - _ => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic( - &left_val, - left.span(), - op.span(), - ) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic( - &right_val, - right.span(), - op.span(), - ) - })?; - Ok(Value::Number(left_num + right_num)) - } - }, - BinaryOp::Sub => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, left.span(), op.span()) - })?; - Ok(Value::Number(left_num - right_num)) - } - BinaryOp::Mult => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Number(left_num * right_num)) - } - BinaryOp::Div => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Number(left_num / right_num)) - } - - BinaryOp::Greater => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Bool(left_num > right_num)) - } - BinaryOp::GreaterEq => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Bool(left_num >= right_num)) - } - BinaryOp::Less => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Bool(left_num < right_num)) - } - BinaryOp::LessEq => { - let left_num = left_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) - })?; - let right_num = right_val.as_number().ok_or_else(|| { - RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) - })?; - Ok(Value::Bool(left_num <= right_num)) - } + Expr::Binary { left, op, right } => self.interpret_binary_op(left, op, right), + Expr::Grouping { inner } => self.interpret_grouping(inner), + Expr::Literal { lit } => { + tracing::trace!("resolving literal"); + Ok(Value::from(lit.as_ref())) + } + Expr::Unary { op, expr } => self.interpret_unary(op, expr), + } + } - BinaryOp::Eq => Ok(Value::Bool(left_val == right_val)), - BinaryOp::NotEq => Ok(Value::Bool(left_val != right_val)), + #[tracing::instrument(name = "binary", skip_all)] + fn interpret_binary_op( + &self, + left: &Spanned, + op: &Spanned, + right: &Spanned, + ) -> Result { + tracing::trace!("evaluating lhs of binary expr"); + let left_val = self.interpret_expr(left)?; + + tracing::trace!("evaluating rhs of binary expr"); + let right_val = self.interpret_expr(right)?; + + match op.as_ref() { + BinaryOp::Add => match (&left_val, &right_val) { + (Value::String(left_str), Value::String(right_str)) => { + let mut s = left_str.clone(); + s.push_str(right_str); + Ok(Value::String(s)) } + (Value::String(_), _) => Err(RuntimeError::non_string_concat( + &right_val, + right.span(), + op.span(), + )), + _ => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Number(left_num + right_num)) + } + }, + BinaryOp::Sub => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, left.span(), op.span()) + })?; + Ok(Value::Number(left_num - right_num)) } - Expr::Grouping { inner } => { - let span = info_span!("grouping"); - let _guard = span.enter(); - tracing::trace!("descending to group"); - // TODO: investigate using more span features here - self.interpret_expr(inner.as_ref()) + BinaryOp::Mult => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Number(left_num * right_num)) } - Expr::Literal { lit } => { - tracing::trace!("resolving literal"); - Ok(Value::from(lit.as_ref())) + BinaryOp::Div => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Number(left_num / right_num)) } - Expr::Unary { op, expr } => { - let span = info_span!("unary"); - let _guard = span.enter(); - tracing::trace!("descending into unary"); - let val = self.interpret_expr(expr)?; - match op.as_ref() { - UnaryOp::Negative => { - tracing::trace!("negating value"); - val.as_number().map(|n| Value::Number(-n)).ok_or_else(|| { - RuntimeError::NegatedNonNumber { - actual_type: val.type_str(), - span: expr.span().into(), - } - }) - } - UnaryOp::Invert => { - tracing::trace!("inverting value"); - Ok(Value::Bool(!val.is_truthy())) + + BinaryOp::Greater => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Bool(left_num > right_num)) + } + BinaryOp::GreaterEq => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Bool(left_num >= right_num)) + } + BinaryOp::Less => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Bool(left_num < right_num)) + } + BinaryOp::LessEq => { + let left_num = left_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&left_val, left.span(), op.span()) + })?; + let right_num = right_val.as_number().ok_or_else(|| { + RuntimeError::non_number_arithmetic(&right_val, right.span(), op.span()) + })?; + Ok(Value::Bool(left_num <= right_num)) + } + + BinaryOp::Eq => Ok(Value::Bool(left_val == right_val)), + BinaryOp::NotEq => Ok(Value::Bool(left_val != right_val)), + } + } + + #[tracing::instrument(name = "grouping", skip_all)] + fn interpret_grouping(&self, inner: &Spanned) -> Result { + tracing::trace!("descending to group"); + // TODO: investigate using more span features here + self.interpret_expr(inner) + } + + #[tracing::instrument(name = "unary", skip_all)] + fn interpret_unary(&self, op: &Spanned, expr: &Spanned) -> Result { + tracing::trace!("descending into unary"); + let val = self.interpret_expr(expr)?; + match op.as_ref() { + UnaryOp::Negative => { + tracing::trace!("negating value"); + val.as_number().map(|n| Value::Number(-n)).ok_or_else(|| { + RuntimeError::NegatedNonNumber { + actual_type: val.type_str(), + span: expr.span().into(), } - } + }) + } + UnaryOp::Invert => { + tracing::trace!("inverting value"); + Ok(Value::Bool(!val.is_truthy())) } } }