Allow negative range step.

This commit is contained in:
Stephen Chung 2021-02-27 15:27:40 +08:00
parent 082111074e
commit 66b557692b
2 changed files with 38 additions and 5 deletions

View File

@ -9,6 +9,16 @@ Bug fixes
* Errors in native Rust functions now contain the correct function call positions. * Errors in native Rust functions now contain the correct function call positions.
Breaking changes
----------------
* Zero step in the `range` function now raises an error instead of creating an infinite stream.
Enhancements
------------
* `range` function now supports negative step and decreasing streams (i.e. to < from).
Version 0.19.13 Version 0.19.13
=============== ===============

View File

@ -3,7 +3,7 @@ use crate::stdlib::{
boxed::Box, boxed::Box,
ops::{Add, Range}, ops::{Add, Range},
}; };
use crate::{def_package, EvalAltResult, INT}; use crate::{def_package, EvalAltResult, Position, INT};
fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> { fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> {
Ok(from..to) Ok(from..to)
@ -16,6 +16,23 @@ where
for<'a> &'a T: Add<&'a T, Output = T>, for<'a> &'a T: Add<&'a T, Output = T>,
T: Variant + Clone + PartialOrd; T: Variant + Clone + PartialOrd;
impl<T> StepRange<T>
where
for<'a> &'a T: Add<&'a T, Output = T>,
T: Variant + Clone + PartialOrd,
{
pub fn new(from: T, to: T, step: T) -> Result<Self, Box<EvalAltResult>> {
if &from + &step == from {
Err(Box::new(EvalAltResult::ErrorArithmetic(
"invalid step value".to_string(),
Position::NONE,
)))
} else {
Ok(Self(from, to, step))
}
}
}
impl<T> Iterator for StepRange<T> impl<T> Iterator for StepRange<T>
where where
for<'a> &'a T: Add<&'a T, Output = T>, for<'a> &'a T: Add<&'a T, Output = T>,
@ -24,12 +41,18 @@ where
type Item = T; type Item = T;
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
if self.0 < self.1 { if self.0 == self.1 {
None
} else if self.0 < self.1 {
let v = self.0.clone(); let v = self.0.clone();
self.0 = self.0.add(&self.2); let n = self.0.add(&self.2);
self.0 = if n >= self.1 { self.1.clone() } else { n };
Some(v) Some(v)
} else { } else {
None let v = self.0.clone();
let n = self.0.add(&self.2);
self.0 = if n <= self.1 { self.1.clone() } else { n };
Some(v)
} }
} }
} }
@ -39,7 +62,7 @@ where
for<'a> &'a T: Add<&'a T, Output = T>, for<'a> &'a T: Add<&'a T, Output = T>,
T: Variant + Clone + PartialOrd, T: Variant + Clone + PartialOrd,
{ {
Ok(StepRange::<T>(from, to, step)) StepRange::<T>::new(from, to, step)
} }
macro_rules! reg_range { macro_rules! reg_range {