openbirch-rs/src/lib/node/range.rs

123 lines
3.2 KiB
Rust

use std::rc::Rc;
use rug::ops::{AddFrom, CompleteRound};
use crate::environment::Environment;
use super::{Error, Node, NodeEnum, Precedence, constant::ConstantValue};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Range {
from: Rc<NodeEnum>,
to: Rc<NodeEnum>,
}
impl Node for Range {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let from_evaluated = self.from.evaluate(env)?;
let to_evaluated = self.to.evaluate(env)?;
Ok(Self::new(from_evaluated, to_evaluated))
}
fn as_string(&self, env: Option<&Environment>) -> String {
format!("{}..{}", self.from.as_string(env), self.to.as_string(env))
}
fn precedence(&self) -> Precedence {
Precedence::Primary
}
}
impl Range {
pub fn new(from: Rc<NodeEnum>, to: Rc<NodeEnum>) -> Rc<NodeEnum> {
Rc::new(Self { from, to }.into())
}
pub fn min(&self) -> Result<&ConstantValue, Error> {
match self.from.as_ref() {
NodeEnum::Constant(c) => Ok(c.get_value()),
_ => Err(Error::MismatchedType(format!(
"Minimum (from) in range was a {}, but it needs to be a Constant",
self.from.type_str()
))),
}
}
pub fn max(&self) -> Result<&ConstantValue, Error> {
match self.to.as_ref() {
NodeEnum::Constant(c) => Ok(c.get_value()),
_ => Err(Error::MismatchedType(format!(
"Maximum (to) in range was a {}, but it needs to be a Constant",
self.to.type_str()
))),
}
}
}
// impl Iterator for &Range {
// type Item = ConstantValue;
//
// fn next(&mut self) -> Option<Self::Item> {
// if self.it.is_none() {
// return None;
// }
//
// let max = match self.to.as_ref() {
// NodeEnum::Constant(c) => c.get_value(),
// _ => panic!("Max is not a fucking constant dipshit"),
// };
//
// let result = {
// let added = self.it.clone().unwrap() + 1;
// let comp = added < max.clone();
// if comp { self.it.clone() } else { None }
// };
// self.it.as_mut().unwrap().add_from(1);
// result
// }
// }
pub struct RangeIter {
it: ConstantValue,
start: ConstantValue,
end: ConstantValue,
}
impl<'a> Iterator for RangeIter {
type Item = ConstantValue;
fn next(&mut self) -> Option<Self::Item> {
let result = {
if self.it < self.end {
Some(self.it.clone())
} else {
None
}
};
self.it += 1;
result
}
}
impl IntoIterator for &Range {
type Item = ConstantValue;
type IntoIter = RangeIter;
fn into_iter(self) -> Self::IntoIter {
let it = match self.from.as_ref() {
NodeEnum::Constant(c) => c.get_value().clone(),
_ => panic!("This range does not have a defined start"),
};
let end = match self.to.as_ref() {
NodeEnum::Constant(c) => c.get_value().clone(),
_ => panic!("This range does not have a defined end"),
};
RangeIter {
start: it.clone(),
end,
it,
}
}
}