Add floating point support for ranges

This commit is contained in:
Jakub Žádník 2021-09-12 14:12:53 +03:00
parent aa7ebdc9ce
commit 2f04c172fe

View File

@ -1,3 +1,5 @@
use std::cmp::Ordering;
use crate::{ use crate::{
ast::{RangeInclusion, RangeOperator}, ast::{RangeInclusion, RangeOperator},
*, *,
@ -150,31 +152,46 @@ impl RangeIterator {
} }
} }
// Compare two floating point numbers. The decision interval for equality is dynamically scaled
// based on the value being compared.
fn compare_floats(val: f64, other: f64) -> Option<Ordering> {
let prec = val * f64::EPSILON;
if (other - val).abs() < prec.abs() {
return Some(Ordering::Equal);
}
val.partial_cmp(&other)
}
impl Iterator for RangeIterator { impl Iterator for RangeIterator {
type Item = Value; type Item = Value;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use std::cmp::Ordering;
if self.done { if self.done {
return None; return None;
} }
let ordering = if matches!(self.end, Value::Nothing { .. }) { let ordering = if matches!(self.end, Value::Nothing { .. }) {
Ordering::Less Some(Ordering::Less)
} else { } else {
match (&self.curr, &self.end) { match (&self.curr, &self.end) {
(Value::Int { val: curr, .. }, Value::Int { val: end, .. }) => curr.cmp(end), (Value::Int { val: curr, .. }, Value::Int { val: end, .. }) => Some(curr.cmp(end)),
// (Value::Float { val: curr, .. }, Value::Float { val: end, .. }) => curr.cmp(end), (Value::Float { val: curr, .. }, Value::Float { val: end, .. }) => compare_floats(*curr, *end),
// (Value::Float { val: curr, .. }, Value::Int { val: end, .. }) => curr.cmp(end), (Value::Float { val: curr, .. }, Value::Int { val: end, .. }) => compare_floats(*curr, *end as f64),
// (Value::Int { val: curr, .. }, Value::Float { val: end, .. }) => curr.cmp(end), (Value::Int { val: curr, .. }, Value::Float { val: end, .. }) => compare_floats(*curr as f64, *end),
_ => { _ => None,
self.done = true;
return Some(Value::Error {
error: ShellError::CannotCreateRange(self.span),
});
}
} }
}; };
let ordering = if let Some(ord) = ordering {
ord
} else {
self.done = true;
return Some(Value::Error {
error: ShellError::CannotCreateRange(self.span),
});
};
let desired_ordering = if self.moves_up { let desired_ordering = if self.moves_up {
Ordering::Less Ordering::Less
} else { } else {