summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-05-04 22:14:51 +0200
committerLaurenz <laurmaedje@gmail.com>2022-05-04 22:14:51 +0200
commit75472fee1a2377f56551fc856cf7511bd55091f0 (patch)
tree72b221fd2bd3ddd2dceb6b443d480fcae9298932
parentba5622b7b90b23e61942a9f4e6460bf9ea0b4bc8 (diff)
Division for lengths
-rw-r--r--src/eval/ops.rs32
-rw-r--r--tests/typ/code/ops-invalid.typ24
-rw-r--r--tests/typ/code/ops.typ27
3 files changed, 71 insertions, 12 deletions
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
index 56bfdf2e..57390a65 100644
--- a/src/eval/ops.rs
+++ b/src/eval/ops.rs
@@ -2,9 +2,9 @@
use std::cmp::Ordering;
-use super::{Dynamic, RawAlign, RawStroke, Smart, StrExt, Value};
+use super::{Dynamic, RawAlign, RawLength, RawStroke, Smart, StrExt, Value};
use crate::diag::StrResult;
-use crate::geom::{Numeric, Spec, SpecAxis};
+use crate::geom::{Numeric, Relative, Spec, SpecAxis};
use crate::model;
use Value::*;
@@ -204,6 +204,8 @@ pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> {
(Length(a), Int(b)) => Length(a / b as f64),
(Length(a), Float(b)) => Length(a / b),
+ (Length(a), Length(b)) => Float(div_length(a, b)?),
+ (Length(a), Relative(b)) if b.rel.is_zero() => Float(div_length(a, b.abs)?),
(Angle(a), Int(b)) => Angle(a / b as f64),
(Angle(a), Float(b)) => Angle(a / b),
@@ -212,9 +214,13 @@ pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> {
(Ratio(a), Int(b)) => Ratio(a / b as f64),
(Ratio(a), Float(b)) => Ratio(a / b),
(Ratio(a), Ratio(b)) => Float(a / b),
+ (Ratio(a), Relative(b)) if b.abs.is_zero() => Float(a / b.rel),
(Relative(a), Int(b)) => Relative(a / b as f64),
(Relative(a), Float(b)) => Relative(a / b),
+ (Relative(a), Length(b)) if a.rel.is_zero() => Float(div_length(a.abs, b)?),
+ (Relative(a), Ratio(b)) if a.abs.is_zero() => Float(a.rel / b),
+ (Relative(a), Relative(b)) => Float(div_relative(a, b)?),
(Fraction(a), Int(b)) => Fraction(a / b as f64),
(Fraction(a), Float(b)) => Fraction(a / b),
@@ -224,6 +230,28 @@ pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> {
})
}
+/// Try to divide two lengths.
+fn div_length(a: RawLength, b: RawLength) -> StrResult<f64> {
+ if a.length.is_zero() && b.length.is_zero() {
+ Ok(a.em / b.em)
+ } else if a.em.is_zero() && b.em.is_zero() {
+ Ok(a.length / b.length)
+ } else {
+ return Err("cannot divide these two lengths".into());
+ }
+}
+
+/// Try to divide two relative lengths.
+fn div_relative(a: Relative<RawLength>, b: Relative<RawLength>) -> StrResult<f64> {
+ if a.rel.is_zero() && b.rel.is_zero() {
+ div_length(a.abs, b.abs)
+ } else if a.abs.is_zero() && b.abs.is_zero() {
+ Ok(a.rel / b.rel)
+ } else {
+ return Err("cannot divide these two relative lengths".into());
+ }
+}
+
/// Compute the logical "not" of a value.
pub fn not(value: Value) -> StrResult<Value> {
match value {
diff --git a/tests/typ/code/ops-invalid.typ b/tests/typ/code/ops-invalid.typ
index 4e7fdb04..3e9e5478 100644
--- a/tests/typ/code/ops-invalid.typ
+++ b/tests/typ/code/ops-invalid.typ
@@ -39,6 +39,26 @@
{(1 + "2", 40% - 1)}
---
+// Error: 14-22 cannot add integer and string
+{ let x = 1; x += "2" }
+
+---
+// Error: 3-12 cannot divide ratio by length
+{ 10% / 5pt }
+
+---
+// Error: 3-12 cannot divide these two lengths
+{ 1em / 5pt }
+
+---
+// Error: 3-19 cannot divide relative length by ratio
+{ (10% + 1pt) / 5% }
+
+---
+// Error: 3-28 cannot divide these two relative lengths
+{ (10% + 1pt) / (20% + 1pt) }
+
+---
// Error: 12-19 cannot subtract integer from ratio
{(1234567, 40% - 1)}
@@ -65,10 +85,6 @@
}
---
-// Error: 14-22 cannot add integer and string
-{ let x = 1; x += "2" }
-
----
// Error: 3-6 cannot mutate a temporary value
{ (x) = "" }
diff --git a/tests/typ/code/ops.typ b/tests/typ/code/ops.typ
index 1f2867bc..33a1a4a4 100644
--- a/tests/typ/code/ops.typ
+++ b/tests/typ/code/ops.typ
@@ -48,7 +48,15 @@
#test({ let x; x = 1 + 4*5 >= 21 and { x = "a"; x + "b" == "ab" }; x }, true)
// Mathematical identities.
-#let nums = (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt)
+#let nums = (
+ 1, 3.14,
+ 12pt, 3em, 12pt + 3em,
+ 45deg,
+ 90%,
+ 13% + 10pt, 5% + 1em + 3pt,
+ 2.3fr,
+)
+
#for v in nums {
// Test plus and minus.
test(v + v - v, v)
@@ -63,18 +71,16 @@
test(v + v, 2.0 * v)
}
- // Lengths cannot be divided by themselves.
- if "length" not in type(v) {
+ if "relative" not in type(v) and ("pt" not in repr(v) or "em" not in repr(v)) {
test(v / v, 1.0)
- test(v / v == 1, true)
}
}
// Make sure length, ratio and relative length
// - can all be added to / subtracted from each other,
// - multiplied with integers and floats,
-// - divided by floats.
-#let dims = (10pt, 30%, 50% + 3cm)
+// - divided by integers and floats.
+#let dims = (10pt, 1em, 10pt + 1em, 30%, 50% + 3cm, 40% + 2em + 1cm)
#for a in dims {
for b in dims {
test(type(a + b), type(a - b))
@@ -87,6 +93,15 @@
}
}
+// Test division of different numeric types with zero components.
+#for a in (0pt, 0em, 0%) {
+ for b in (10pt, 10em, 10%) {
+ test((2 * b) / b, 2)
+ test((a + b * 2) / b, 2)
+ test(b / (b * 2 + a), 0.5)
+ }
+}
+
---
// Test boolean operators.