use super::SrcValue;
use crate::value::{Numeric, ValueRange};
use crate::{Error, Invalid, ScopeRef};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct SrcRange {
from: SrcValue,
to: SrcValue,
inclusive: bool,
}
impl SrcRange {
pub fn evaluate(&self, scope: ScopeRef) -> Result<ValueRange, Error> {
let (from, unit) = self.from.eval_map(scope.clone(), |v| {
let v = v
.numeric_value()
.map_err(|v| Invalid::not(&v, "a number"))?;
let unit = v.unit;
let v = v.value.into_integer().map_err(|e| {
Invalid::not(&Numeric::new(e, unit.clone()), "an int")
})?;
Ok((v, unit))
})?;
let to = self.to.eval_map(scope.clone(), |v| {
let v = v
.numeric_value()
.map_err(|v| Invalid::not(&v, "a number"))?;
let v = if unit.is_none() || v.is_no_unit() {
v.value
} else if let Some(scaled) = v.as_unitset(&unit) {
scaled
} else {
return Err(Invalid::expected_to(
&v,
&format!("have unit {unit}"),
));
};
let v = v.into_integer().map_err(|e| {
Invalid::not(&Numeric::new(e, unit.clone()), "an int")
})?;
Ok(v)
})?;
Ok(ValueRange::new(from, to, self.inclusive, unit))
}
}
pub mod parser {
use super::SrcRange;
use crate::parser::util::ignore_comments;
use crate::parser::{single_value_p, PResult, Span};
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::value;
use nom::sequence::{delimited, terminated};
use nom::Parser as _;
pub fn src_range(input: Span) -> PResult<SrcRange> {
let (input, from) = delimited(
terminated(tag("from"), ignore_comments),
single_value_p,
ignore_comments,
)
.parse(input)?;
let (input, inclusive) = terminated(
alt((value(true, tag("through")), value(false, tag("to")))),
ignore_comments,
)
.parse(input)?;
let (input, to) =
terminated(single_value_p, ignore_comments).parse(input)?;
Ok((
input,
SrcRange {
from,
to,
inclusive,
},
))
}
}