summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-09-11 17:26:56 +0200
committerLaurenz <laurmaedje@gmail.com>2023-09-11 17:38:03 +0200
commit2dc000daeba1718673b0f0025b31a78c001223d1 (patch)
tree2ec20647f8511074b2fcc660263d705e917e3e91
parent3a979e88da7be6240821ba8acfdd376b7f4e0f09 (diff)
Type compatibility
For now, types can be used like strings in operations to prevent breakage of many packages. Hopefully, we can get rid of this in the future.
-rw-r--r--crates/typst/src/eval/ops.rs18
-rw-r--r--crates/typst/src/eval/ty.rs8
-rw-r--r--tests/typ/compiler/type-compatibility.typ10
3 files changed, 36 insertions, 0 deletions
diff --git a/crates/typst/src/eval/ops.rs b/crates/typst/src/eval/ops.rs
index e44c3a41..23a32416 100644
--- a/crates/typst/src/eval/ops.rs
+++ b/crates/typst/src/eval/ops.rs
@@ -34,6 +34,11 @@ pub fn join(lhs: Value, rhs: Value) -> StrResult<Value> {
(Symbol(a), Content(b)) => Content(item!(text)(a.get().into()) + b),
(Array(a), Array(b)) => Array(a + b),
(Dict(a), Dict(b)) => Dict(a + b),
+
+ // Type compatibility.
+ (Type(a), Str(b)) => Str(format_str!("{a}{b}")),
+ (Str(a), Type(b)) => Str(format_str!("{a}{b}")),
+
(a, b) => mismatch!("cannot join {} with {}", a, b),
})
}
@@ -119,6 +124,10 @@ pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
(Datetime(a), Duration(b)) => Datetime(a + b),
(Duration(a), Datetime(b)) => Datetime(b + a),
+ // Type compatibility.
+ (Type(a), Str(b)) => Str(format_str!("{a}{b}")),
+ (Str(a), Type(b)) => Str(format_str!("{a}{b}")),
+
(Dyn(a), Dyn(b)) => {
// Alignments can be summed.
if let (Some(&a), Some(&b)) = (a.downcast::<Align>(), b.downcast::<Align>()) {
@@ -380,6 +389,10 @@ pub fn equal(lhs: &Value, rhs: &Value) -> bool {
(&Relative(a), &Length(b)) => a.abs == b && a.rel.is_zero(),
(&Relative(a), &Ratio(b)) => a.rel == b && a.abs.is_zero(),
+ // Type compatibility.
+ (Type(a), Str(b)) => a.compat_name() == b.as_str(),
+ (Str(a), Type(b)) => a.as_str() == b.compat_name(),
+
_ => false,
}
}
@@ -449,6 +462,11 @@ pub fn contains(lhs: &Value, rhs: &Value) -> Option<bool> {
(Dyn(a), Str(b)) => a.downcast::<Regex>().map(|regex| regex.is_match(b)),
(Str(a), Dict(b)) => Some(b.contains(a)),
(a, Array(b)) => Some(b.contains(a.clone())),
+
+ // Type compatibility.
+ (Type(a), Str(b)) => Some(b.as_str().contains(a.compat_name())),
+ (Type(a), Dict(b)) => Some(b.contains(a.compat_name())),
+
_ => Option::None,
}
}
diff --git a/crates/typst/src/eval/ty.rs b/crates/typst/src/eval/ty.rs
index f7832672..da3c91aa 100644
--- a/crates/typst/src/eval/ty.rs
+++ b/crates/typst/src/eval/ty.rs
@@ -80,6 +80,14 @@ impl Type {
}
}
+// Type compatibility.
+impl Type {
+ /// The type's backwards-compatible name.
+ pub fn compat_name(&self) -> &str {
+ self.long_name()
+ }
+}
+
#[scope]
impl Type {
/// Determines a value's type.
diff --git a/tests/typ/compiler/type-compatibility.typ b/tests/typ/compiler/type-compatibility.typ
new file mode 100644
index 00000000..664981f4
--- /dev/null
+++ b/tests/typ/compiler/type-compatibility.typ
@@ -0,0 +1,10 @@
+// Test compatibility between types and strings.
+// Ref: false
+
+---
+#test(type(10), int)
+#test(type(10), "integer")
+#test("is " + type(10), "is integer")
+#test(int in ("integer", "string"), true)
+#test(int in "integers or strings", true)
+#test(str in "integers or strings", true)