summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-08-31 12:59:53 +0200
committerLaurenz <laurmaedje@gmail.com>2021-08-31 12:59:53 +0200
commit3481d8cc81a2b3a14118869c7f0ffe204ff3efc8 (patch)
tree907efa2e092366a24e25243854b1a4e088cc04a9 /src/eval
parentee84bf74083f5b9cc88a2a0a968dc905b1eef22c (diff)
More utility functions
- join("a", "b", "c", sep: ", ") - int("12") - float("31.4e-1") - str(10) - sorted((3, 2, 1))
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/array.rs21
-rw-r--r--src/eval/mod.rs3
-rw-r--r--src/eval/ops.rs13
-rw-r--r--src/eval/str.rs23
-rw-r--r--src/eval/value.rs5
5 files changed, 62 insertions, 3 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs
index acf44ab2..bae89c4b 100644
--- a/src/eval/array.rs
+++ b/src/eval/array.rs
@@ -1,3 +1,4 @@
+use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::iter::FromIterator;
@@ -80,6 +81,26 @@ impl Array {
self.0.iter()
}
+ /// Return a sorted version of this array.
+ ///
+ /// Returns an error if two values could not be compared.
+ pub fn sorted(mut self) -> StrResult<Self> {
+ let mut result = Ok(());
+ Rc::make_mut(&mut self.0).sort_by(|a, b| {
+ a.partial_cmp(b).unwrap_or_else(|| {
+ if result.is_ok() {
+ result = Err(format!(
+ "cannot compare {} with {}",
+ a.type_name(),
+ b.type_name(),
+ ));
+ }
+ Ordering::Equal
+ })
+ });
+ result.map(|_| self)
+ }
+
/// Repeat this array `n` times.
pub fn repeat(&self, n: i64) -> StrResult<Self> {
let count = usize::try_from(n)
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index b8561a87..f48312c8 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -5,13 +5,14 @@ mod array;
#[macro_use]
mod dict;
#[macro_use]
+mod str;
+#[macro_use]
mod value;
mod capture;
mod function;
mod ops;
mod scope;
mod state;
-mod str;
mod template;
mod walk;
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
index 6d34b877..c7a45614 100644
--- a/src/eval/ops.rs
+++ b/src/eval/ops.rs
@@ -291,12 +291,21 @@ pub fn compare(lhs: &Value, rhs: &Value) -> Option<Ordering> {
match (lhs, rhs) {
(Bool(a), Bool(b)) => a.partial_cmp(b),
(Int(a), Int(b)) => a.partial_cmp(b),
- (Int(a), Float(b)) => (*a as f64).partial_cmp(b),
- (Float(a), Int(b)) => a.partial_cmp(&(*b as f64)),
(Float(a), Float(b)) => a.partial_cmp(b),
(Angle(a), Angle(b)) => a.partial_cmp(b),
(Length(a), Length(b)) => a.partial_cmp(b),
+ (Relative(a), Relative(b)) => a.partial_cmp(b),
+ (Fractional(a), Fractional(b)) => a.partial_cmp(b),
(Str(a), Str(b)) => a.partial_cmp(b),
+
+ // Some technically different things should be comparable.
+ (&Int(a), &Float(b)) => (a as f64).partial_cmp(&b),
+ (&Float(a), &Int(b)) => a.partial_cmp(&(b as f64)),
+ (&Length(a), &Linear(b)) if b.rel.is_zero() => a.partial_cmp(&b.abs),
+ (&Relative(a), &Linear(b)) if b.abs.is_zero() => a.partial_cmp(&b.rel),
+ (&Linear(a), &Length(b)) if a.rel.is_zero() => a.abs.partial_cmp(&b),
+ (&Linear(a), &Relative(b)) if a.abs.is_zero() => a.rel.partial_cmp(&b),
+
_ => Option::None,
}
}
diff --git a/src/eval/str.rs b/src/eval/str.rs
index a358cd9f..099a4363 100644
--- a/src/eval/str.rs
+++ b/src/eval/str.rs
@@ -1,3 +1,4 @@
+use std::borrow::Borrow;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::ops::{Add, AddAssign, Deref};
@@ -5,6 +6,16 @@ use std::ops::{Add, AddAssign, Deref};
use crate::diag::StrResult;
use crate::util::EcoString;
+/// Create a new [`Str`] from a format string.
+macro_rules! format_str {
+ ($($tts:tt)*) => {{
+ use std::fmt::Write;
+ let mut s = $crate::util::EcoString::new();
+ write!(s, $($tts)*).unwrap();
+ $crate::eval::Str::from(s)
+ }};
+}
+
/// A string value with inline storage and clone-on-write semantics.
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Str(EcoString);
@@ -92,6 +103,18 @@ impl AddAssign for Str {
}
}
+impl AsRef<str> for Str {
+ fn as_ref(&self) -> &str {
+ self
+ }
+}
+
+impl Borrow<str> for Str {
+ fn borrow(&self) -> &str {
+ self
+ }
+}
+
impl From<char> for Str {
fn from(c: char) -> Self {
Self(c.into())
diff --git a/src/eval/value.rs b/src/eval/value.rs
index 5edf0362..77cb766c 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -88,6 +88,11 @@ impl Value {
{
T::cast(self)
}
+
+ /// Join the value with another value.
+ pub fn join(self, rhs: Self) -> StrResult<Self> {
+ ops::join(self, rhs)
+ }
}
impl Default for Value {