summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/library/mod.rs1
-rw-r--r--src/library/utility.rs30
2 files changed, 31 insertions, 0 deletions
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 97d30e31..4ea248ce 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -139,6 +139,7 @@ pub fn new() -> Scope {
std.def_func("max", max);
std.def_func("even", even);
std.def_func("odd", odd);
+ std.def_func("mod", modulo);
std.def_func("range", range);
std.def_func("rgb", rgb);
std.def_func("lower", lower);
diff --git a/src/library/utility.rs b/src/library/utility.rs
index 1909dff2..2935d458 100644
--- a/src/library/utility.rs
+++ b/src/library/utility.rs
@@ -170,6 +170,36 @@ pub fn odd(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
}
+/// The modulo of two numbers.
+pub fn modulo(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
+ let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
+ let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
+
+ let (a, b) = match (v1, v2) {
+ (Value::Int(a), Value::Int(b)) => match a.checked_rem(b) {
+ Some(res) => return Ok(res.into()),
+ None => bail!(span2, "divisor must not be zero"),
+ },
+ (Value::Int(a), Value::Float(b)) => (a as f64, b),
+ (Value::Float(a), Value::Int(b)) => (a, b as f64),
+ (Value::Float(a), Value::Float(b)) => (a, b),
+ (Value::Int(_), b) | (Value::Float(_), b) => bail!(
+ span2,
+ format!("expected integer or float, found {}", b.type_name())
+ ),
+ (a, _) => bail!(
+ span1,
+ format!("expected integer or float, found {}", a.type_name())
+ ),
+ };
+
+ if b == 0.0 {
+ bail!(span2, "divisor must not be zero");
+ }
+
+ Ok((a % b).into())
+}
+
/// Find the minimum or maximum of a sequence of values.
fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> {
let mut extremum = args.expect::<Value>("value")?;