diff --git a/src/model/ops.rs b/src/model/ops.rs index 9da9b0cca..7acf917db 100644 --- a/src/model/ops.rs +++ b/src/model/ops.rs @@ -1,10 +1,11 @@ //! Operations on values. +use std::cmp::Ordering; + use super::{Regex, Value}; use crate::diag::StrResult; use crate::geom::{Axes, Axis, GenAlign, Length, Numeric, PartialStroke, Rel, Smart}; use crate::util::format_eco; -use std::cmp::Ordering; use Value::*; /// Bail with a type mismatch error. @@ -195,6 +196,10 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult { /// Compute the quotient of two values. pub fn div(lhs: Value, rhs: Value) -> StrResult { + if is_zero(&rhs) { + Err("cannot divide by zero")?; + } + Ok(match (lhs, rhs) { (Int(a), Int(b)) => Float(a as f64 / b as f64), (Int(a), Float(b)) => Float(a as f64 / b), @@ -229,6 +234,20 @@ pub fn div(lhs: Value, rhs: Value) -> StrResult { }) } +/// Whether a value is a numeric zero. +fn is_zero(v: &Value) -> bool { + match *v { + Int(v) => v == 0, + Float(v) => v == 0.0, + Length(v) => v.is_zero(), + Angle(v) => v.is_zero(), + Ratio(v) => v.is_zero(), + Relative(v) => v.is_zero(), + Fraction(v) => v.is_zero(), + _ => false, + } +} + /// Try to divide two lengths. fn try_div_length(a: Length, b: Length) -> StrResult { a.try_div(b).ok_or_else(|| "cannot divide these two lengths".into()) diff --git a/tests/typ/compiler/ops-invalid.typ b/tests/typ/compiler/ops-invalid.typ index 3e9e54788..3d41a3d1f 100644 --- a/tests/typ/compiler/ops-invalid.typ +++ b/tests/typ/compiler/ops-invalid.typ @@ -33,6 +33,18 @@ // Error: 2-13 cannot apply '<=' to length and length {1em <= 10pt} +--- +// Error: 2-11 cannot divide by zero +{1.2 / 0.0} + +--- +// Error: 2-7 cannot divide by zero +{1 / 0} + +--- +// Error: 2-14 cannot divide by zero +{15deg / 0deg} + --- // Special messages for +, -, * and /. // Error: 03-10 cannot add integer and string