diff options
Diffstat (limited to 'src/eval/ops.rs')
| -rw-r--r-- | src/eval/ops.rs | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/src/eval/ops.rs b/src/eval/ops.rs index 732bfb14..e40fa78d 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -1,7 +1,9 @@ use std::cmp::Ordering; +use std::convert::TryFrom; use super::Value; use crate::diag::StrResult; +use crate::util::EcoString; use Value::*; /// Bail with a type mismatch error. @@ -150,8 +152,8 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> { (Fractional(a), Float(b)) => Fractional(a * b), (Int(a), Fractional(b)) => Fractional(a as f64 * b), - (Str(a), Int(b)) => Str(a.repeat(b)?), - (Int(a), Str(b)) => Str(b.repeat(a)?), + (Str(a), Int(b)) => Str(repeat_str(a, b)?), + (Int(a), Str(b)) => Str(repeat_str(b, a)?), (Array(a), Int(b)) => Array(a.repeat(b)?), (Int(a), Array(b)) => Array(b.repeat(a)?), (Template(a), Int(b)) => Template(a.repeat(b)?), @@ -161,6 +163,16 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> { }) } +/// Repeat a string a number of times. +fn repeat_str(string: EcoString, n: i64) -> StrResult<EcoString> { + let n = usize::try_from(n) + .ok() + .and_then(|n| string.len().checked_mul(n).map(|_| n)) + .ok_or_else(|| format!("cannot repeat this string {} times", n))?; + + Ok(string.repeat(n)) +} + /// Compute the quotient of two values. pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> { Ok(match (lhs, rhs) { |
