use std::{ fmt::Display, sync::{Arc, Mutex}, }; use crate::{ data::{ self, function::{Function, FunctionT}, int::{Int, IntT, INT_MAX}, Data, MersData, MersType, MersTypeWInfo, Type, }, errors::CheckError, info::DisplayInfo, program::{self, run::CheckInfo}, }; use super::Config; impl Config { /// Adds functions to deal with iterables /// `for_each: fn` executes a function once for each element of the iterable /// `map: fn` maps each value in the iterable to a new one by applying a transformation function /// `filter: fn` filters the iterable by removing all elements where the filter function doesn't return true /// `filter_map: fn` combines filter and map. requires that the function returns ()/(t). /// `map_while: fn` maps while the map-function returns (d), ends the iterator once () is returned. /// `take: fn` takes at most so many elements from the iterator. /// `enumerate: fn` transforms an iterator over T into one over (Int, T), where Int is the index of the element /// `any: fn` returns true if any element of the iterator are true /// `all: fn` returns true if all elements of the iterator are true /// `range_inc: fn` returns an iterable `Range` starting at the first argument, counting up to the second one (inclusive). /// `range_exc: fn` returns an iterable `Range` starting at the first argument, counting up to the second one (exclusive). pub fn with_iters(self) -> Self { self .add_type("Range".to_owned(), Err(Arc::new(|str, _i| { if let Some((val, end)) = str.split_once("..") { if let (Ok(val), Ok(end)) = (val.trim().parse(), end.trim().parse()) { Ok(RangeT(val, end)) } else { Err(CheckError::from(format!("bad Range type, got <{str}> but expected where start and end are Ints"))) } } else { Err(CheckError::from(format!("bad Range type, got <{str}> but expected "))) }.map(|v| Arc::new(Type::new(v))) }))) .add_var("range_inc", Function::new_generic( |a, i| { let mut o = Type::empty(); for a in &a.types { let a = a.as_any().downcast_ref::().ok_or_else(|| CheckError::from(format!("expected 2- or 3-tuple, but found {}", a.with_info(i))))?; if a.0.len() == 2 { let mut min = None; let mut max = None; for v in a.0[0].types.iter().chain(a.0[1].types.iter()) { let v = v.as_any().downcast_ref::().ok_or_else(|| CheckError::from(format!("expected int as first argument, but got {}", v.with_info(i))))?; if min.is_none_or(|min| min > v.0) { min = Some(v.0); } if max.is_none_or(|max| max < v.1) { max = Some(v.1); } } if let (Some(min), Some(max)) = (min, max) { o.add(Arc::new(RangeT(min, max))); } } else { return Err(CheckError::from(format!("expected 2-tuple, but found {}", a.with_info(i)))); } } Ok(o) }, |a, _| { let a = a.get(); let a = a.as_any().downcast_ref::().unwrap(); let (v, e) = (a.0[0].get(), a.0[1].get()); let (v, e) = (v.as_any().downcast_ref::().unwrap(), e.as_any().downcast_ref::().unwrap()); Ok(Data::new(Range(v.0, e.0))) } )) .add_var("range_exc", Function::new_generic( |a, i| { let mut o = Type::empty(); for a in &a.types { let a = a.as_any().downcast_ref::().ok_or_else(|| CheckError::from(format!("expected 2- or 3-tuple, but found {}", a.with_info(i))))?; if a.0.len() == 2 { let mut min = None; let mut max = None; for v in a.0[0].types.iter().chain(a.0[1].types.iter()) { let v = v.as_any().downcast_ref::().ok_or_else(|| CheckError::from(format!("expected int as first argument, but got {}", v.with_info(i))))?; if min.is_none_or(|min| min > v.0) { min = Some(v.0); } if max.is_none_or(|max| max < v.1) { max = Some(v.1); } } if let (Some(min), Some(max)) = (min, max) { if let Some(max) = max.checked_sub(1) { o.add(Arc::new(RangeT(min, max))); } else { o.add(Arc::new(RangeT(min.saturating_add(1), max))); } } } else { return Err(CheckError::from(format!("expected 2-tuple, but found {}", a.with_info(i)))); } } Ok(o) }, |a, _| { let a = a.get(); let a = a.as_any().downcast_ref::().unwrap(); let (v, e) = (a.0[0].get(), a.0[1].get()); let (v, e) = (v.as_any().downcast_ref::().unwrap(), e.as_any().downcast_ref::().unwrap()); if let Some(e) = e.0.checked_sub(1) { Ok(Data::new(Range(v.0, e))) } else { Ok(Data::new(Range(v.0.saturating_add(1), e.0))) } } )) .add_var("any", genfunc_iter_in_val_out("all".to_string(), data::bool::bool_type(), data::bool::bool_type(), |a, i| { for v in a.get().iterable(&i.global).unwrap().map(|v| v.map(|v| v.get().as_any().downcast_ref::().is_some_and(|v| v.0))) { if v? { return Ok(Data::new(data::bool::Bool(true))); } } Ok(Data::new(data::bool::Bool(false))) })) .add_var("all", genfunc_iter_in_val_out("all".to_string(), data::bool::bool_type(), data::bool::bool_type(), |a, i| { for v in a.get().iterable(&i.global).unwrap().map(|v| v.map(|v| v.get().as_any().downcast_ref::().is_some_and(|v| v.0))) { if !v? { return Ok(Data::new(data::bool::Bool(false))); } } Ok(Data::new(data::bool::Bool(true))) })) .add_var( "for_each", data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|a, i| { for a in &a.types { if let Some(tuple) = a.as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) { if let (Some(iter), Some(f)) = ( v.iterable(), f.types .iter() .map(|t| { t.executable() }) .collect::>>(), ) { for f in f { let _ret = f.o(&iter)?; // if !ret.is_zero_tuple() { // return Err(format!("for_each function must return (), not {ret}").into()); // } } } else { return Err(format!( "for_each called on tuple not containing iterable and function: {} is {}", v.with_info(i), if v.iterable().is_some() { "iterable" } else { "not iterable" }, ).into()); } } else { return Err(format!( "for_each called on tuple with len < 2" ).into()); } } else { return Err(format!("for_each called on non-tuple").into()); } } Ok(Type::empty_tuple()) })), run: Arc::new(|a, i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { if let Some(iter) = v.get().iterable(&i.global) { let f = f.get(); for v in iter { f.execute(v?, &i.global).unwrap()?; } Ok(Data::empty_tuple()) } else { return Err( "for_each called on tuple not containing iterable and function (not an iterable)".into() ); } } else { return Err("for_each called on tuple with len < 2".into()); } } else { return Err("for_each called on non-tuple".into()); } }), inner_statements: None, }, ) .add_var( "map", genfunc_iter_and_func("map", ItersT::Map, Iters::Map) ) .add_var( "filter", genfunc_iter_and_func("filter", ItersT::Filter, Iters::Filter), ) .add_var( "filter_map", genfunc_iter_and_func("filter_map", ItersT::FilterMap, Iters::FilterMap), ) .add_var( "map_while", genfunc_iter_and_func("map_while", ItersT::MapWhile, Iters::MapWhile), ) .add_var("take", genfunc_iter_and_arg("take", |_: &data::int::IntT| ItersT::Take, |v: &data::int::Int| { Iters::Take(v.0.max(0).try_into().unwrap_or(usize::MAX)) }, &data::int::IntT(0, INT_MAX))) .add_var( "enumerate", data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|a, i| { let data = if let Some(a) = a.iterable() { a } else { return Err(format!("cannot call enumerate on non-iterable type {}.", a.with_info(i)).into()); }; Ok(Type::new(IterT::new(ItersT::Enumerate, data, i)?)) })), run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))), inner_statements: None, }, ) .add_var( "chain", data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|a, i| { let data = if let Some(a) = a.iterable() { a } else { return Err(format!("cannot call chain on non-iterable type {}.", a.with_info(i)).into()); }; Ok(Type::new(IterT::new(ItersT::Chained, data, i)?)) })), run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))), inner_statements: None, }, ) } } fn genfunc_iter_and_func( name: &'static str, ft: impl Fn(FunctionT) -> ItersT + Send + Sync + 'static, fd: impl Fn(Data) -> Iters + Send + Sync + 'static, ) -> data::function::Function { fn iter_out_arg( a: &Type, i: &mut CheckInfo, name: &str, func: impl Fn(FunctionT) -> ItersT + Sync + Send, ) -> Result { let mut out = Type::empty(); for t in a.types.iter() { if let Some(t) = t.as_any().downcast_ref::() { if t.0.len() != 2 { return Err(format!("cannot call {name} on tuple where len != 2").into()); } if let Some(v) = t.0[0].iterable() { for f in t.0[1].types.iter() { if let Some(f) = f.executable() { out.add(Arc::new(IterT::new(func(f), v.clone(), i)?)); } else { return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {}", t.0[1].with_info(i), a.with_info(i)).into()); } } } else { return Err(format!( "cannot call {name} on non-iterable type {}, which is part of {}.", t.with_info(i), a.with_info(i) ) .into()); } } } Ok(out) } data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(move |a, i| iter_out_arg(a, i, name, |f| ft(f)))), run: Arc::new(move |a, _i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { Ok(Data::new(Iter(fd(f.clone()), v.clone()))) } else { return Err("{name} called on tuple with len < 2".into()); } } else { return Err("{name} called on non-tuple".into()); } }), inner_statements: None, } } fn genfunc_iter_and_arg( name: &'static str, ft: impl Fn(&T) -> ItersT + Send + Sync + 'static, fd: impl Fn(&D) -> Iters + Send + Sync + 'static, type_sample: &'static T, ) -> data::function::Function { fn iter_out_arg( a: &Type, i: &mut CheckInfo, name: &str, func: impl Fn(&T) -> ItersT + Sync + Send, type_sample: &T, ) -> Result { let type_sample = type_sample.with_info(i); let mut out = Type::empty(); for t in a.types.iter() { if let Some(t) = t.as_any().downcast_ref::() { if t.0.len() != 2 { return Err(format!("cannot call {name} on tuple where len != 2").into()); } if let Some(v) = t.0[0].iterable() { for f in t.0[1].types.iter() { if let Some(f) = f.as_any().downcast_ref::() { out.add(Arc::new(IterT::new(func(f), v.clone(), i)?)); } else { return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {}", t.0[1].with_info(i), a.with_info(i)).into()); } } } else { return Err(format!( "cannot call {name} on non-iterable type {}, which is part of {}.", t.with_info(i), a.with_info(i) ) .into()); } } } Ok(out) } data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(move |a, i| { iter_out_arg(a, i, name, |f: &T| ft(f), type_sample) })), run: Arc::new(move |a, _i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { if let Some(f) = f.get().as_any().downcast_ref::() { Ok(Data::new(Iter(fd(f), v.clone()))) } else { return Err("{name} called on tuple not containing function".into()); } } else { return Err("{name} called on tuple with len < 2".into()); } } else { return Err("{name} called on non-tuple".into()); } }), inner_statements: None, } } #[derive(Clone, Debug)] pub enum Iters { Map(Data), Filter(Data), FilterMap(Data), MapWhile(Data), Take(usize), Enumerate, Chained, } #[derive(Clone, Debug)] pub enum ItersT { Map(data::function::FunctionT), Filter(data::function::FunctionT), FilterMap(data::function::FunctionT), MapWhile(data::function::FunctionT), Take, Enumerate, Chained, } #[derive(Clone, Debug)] pub struct Iter(pub Iters, pub Data); #[derive(Clone, Debug)] pub struct IterT(pub ItersT, pub Type, pub Type); impl MersData for Iter { fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{self}") } fn is_eq(&self, _other: &dyn MersData) -> bool { false } fn iterable( &self, gi: &crate::program::run::RunLocalGlobalInfo, ) -> Option>>> { let gi = gi.clone(); Some(match &self.0 { Iters::Map(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable(&gi)?.map(move |v| { f.get() .execute(v?, &gi) .ok_or_else(|| CheckError::from("called map with non-function argument"))? })) } Iters::Filter(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable(&gi)?.filter_map(move |v| { match v { Ok(v) => match f.get().execute(v.clone(), &gi) { Some(Ok(f)) => { if f.get() .as_any() .downcast_ref::() .is_some_and(|b| b.0) { Some(Ok(v)) } else { None } } Some(Err(e)) => Some(Err(e)), None => Some(Err(CheckError::from( "called filter with non-function argument", ))), }, Err(e) => Some(Err(e)), } })) } Iters::FilterMap(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable(&gi)?.filter_map(move |v| match v { Ok(v) => match f.get().execute(v, &gi) { Some(Ok(r)) => Some(Ok(r.one_tuple_content()?)), Some(Err(e)) => Some(Err(e)), None => Some(Err(CheckError::from( "called filter_map with non-function argument", ))), }, Err(e) => Some(Err(e)), })) } Iters::MapWhile(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable(&gi)?.map_while(move |v| match v { Ok(v) => match f.get().execute(v, &gi) { Some(Ok(r)) => Some(Ok(r.one_tuple_content()?)), Some(Err(e)) => Some(Err(e)), None => Some(Err(CheckError::from( "called map_while with non-function argument", ))), }, Err(e) => Some(Err(e)), })) } Iters::Take(limit) => Box::new(self.1.get().iterable(&gi)?.take(*limit)), Iters::Enumerate => { Box::new( self.1 .get() .iterable(&gi)? .enumerate() .map(|(i, v)| match v { Ok(v) => Ok(Data::new(data::tuple::Tuple(vec![ Data::new(data::int::Int(i as _)), v, ]))), Err(e) => Err(e), }), ) } Iters::Chained => { match self .1 .get() .iterable(&gi)? .map(move |v| Ok(v?.get().iterable(&gi))) .collect::>, CheckError>>() { Ok(Some(iters)) => Box::new(iters.into_iter().flatten()), Ok(None) => return None, Err(e) => Box::new([Err(e)].into_iter()), } } }) } fn clone(&self) -> Box { Box::new(Clone::clone(self)) } fn as_type(&self) -> data::Type { Type::new( IterT::new( self.0.as_type(), self.1.get().as_type(), &crate::info::Info::neverused(), ) .unwrap(), ) } fn as_any(&self) -> &dyn std::any::Any { self } fn mut_any(&mut self) -> &mut dyn std::any::Any { self } fn to_any(self) -> Box { Box::new(self) } } impl IterT { /// `i` is only used for errors (this is important for `as_type()`) pub fn new(iter: ItersT, data: Type, i: &CheckInfo) -> Result { let t = match &iter { ItersT::Map(f) => f.o(&data)?, ItersT::Filter(f) => { if f.o(&data)?.is_included_in(&data::bool::bool_type()) { data.clone() } else { return Err(format!( "Iter:Filter, but function doesn't return bool for argument {}.", data.with_info(&i) ) .into()); } } ItersT::FilterMap(f) => { if let Some(v) = f.o(&data)?.one_tuple_possible_content() { v } else { return Err( format!("Iter:FilterMap, but function doesn't return ()/(t).").into(), ); } } ItersT::MapWhile(f) => { if let Some(t) = f.o(&data)?.one_tuple_possible_content() { t } else { return Err( format!("Iter:MapWhile, but function doesn't return ()/(t).").into(), ); } } ItersT::Take => data.clone(), ItersT::Enumerate => Type::new(data::tuple::TupleT(vec![ Type::new(data::int::IntT(0, INT_MAX)), data.clone(), ])), ItersT::Chained => { if let Some(out) = data.iterable() { out } else { return Err(format!( "Cannot create a chain from an iterator over the non-iterator type {}.", data.with_info(i) ) .into()); } } }; Ok(Self(iter, data, t)) } } impl MersType for IterT { fn display( &self, info: &crate::info::DisplayInfo<'_>, f: &mut std::fmt::Formatter, ) -> std::fmt::Result { write!(f, "", self.2.with_display(info)) } fn is_same_type_as(&self, other: &dyn MersType) -> bool { if let Some(other) = other.as_any().downcast_ref::() { self.2.is_same_type_as(&other.2) } else { false } } fn is_included_in(&self, target: &dyn MersType) -> bool { if let Some(target) = target.as_any().downcast_ref::() { self.2.is_included_in(&target.2) } else { false } } fn iterable(&self) -> Option { Some(self.2.clone()) } fn subtypes(&self, acc: &mut Type) { // NOTE: This might not be good enough acc.add(Arc::new(self.clone())); } fn as_any(&self) -> &dyn std::any::Any { self } fn mut_any(&mut self) -> &mut dyn std::any::Any { self } fn to_any(self) -> Box { Box::new(self) } } impl Display for Iter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "") } } impl Iters { fn as_type(&self) -> ItersT { match self { Self::Map(f) => ItersT::Map(f.get().executable().unwrap()), Self::Filter(f) => ItersT::Filter(f.get().executable().unwrap()), Self::FilterMap(f) => ItersT::FilterMap(f.get().executable().unwrap()), Self::MapWhile(f) => ItersT::MapWhile(f.get().executable().unwrap()), Self::Take(_) => ItersT::Take, Self::Enumerate => ItersT::Enumerate, Self::Chained => ItersT::Chained, } } } fn genfunc_iter_in_val_out( name: String, iter_type: Type, out_type: Type, run: impl Fn(Data, &mut crate::info::Info) -> Result + Send + Sync + 'static, ) -> Function { Function { info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), out: Ok(Arc::new(move |a, i| { if let Some(iter_over) = a.iterable() { if iter_over.is_included_in(&iter_type) { Ok(out_type.clone()) } else { Err(format!( "Cannot call function {name} on iterator over type {}, which isn't {}.", a.with_info(i), iter_type.with_info(i) ) .into()) } } else { Err(format!( "Cannot call function {name} on non-iterable type {}.", a.with_info(i) ) .into()) } })), run: Arc::new(run), inner_statements: None, } } #[derive(Clone, Debug, PartialEq)] pub struct Range(isize, isize); #[derive(Clone, Debug, PartialEq)] pub struct RangeT(isize, isize); impl MersData for Range { fn display(&self, _info: &DisplayInfo, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}.range_inc({})", self.0, self.1) } fn iterable( &self, _gi: &crate::program::run::RunLocalGlobalInfo, ) -> Option>>> { Some(Box::new( RangeInt(self.0, self.1, false).map(|v| Ok(Data::new(Int(v)))), )) } fn clone(&self) -> Box { Box::new(Clone::clone(self)) } fn is_eq(&self, other: &dyn MersData) -> bool { other .as_any() .downcast_ref::() .is_some_and(|other| other == self) } fn as_type(&self) -> Type { Type::new(RangeT(self.0, self.1)) } fn as_any(&self) -> &dyn std::any::Any { self } fn mut_any(&mut self) -> &mut dyn std::any::Any { self } fn to_any(self) -> Box { Box::new(self) } } impl MersType for RangeT { fn display( &self, _info: &crate::info::DisplayInfo<'_>, f: &mut std::fmt::Formatter, ) -> std::fmt::Result { write!(f, "Range<{}..{}>", self.0, self.1) } fn iterable(&self) -> Option { Some(Type::new(IntT(self.0, self.0.max(self.1)))) } fn is_same_type_as(&self, other: &dyn MersType) -> bool { other .as_any() .downcast_ref::() .is_some_and(|other| *self == *other) } fn is_included_in(&self, target: &dyn MersType) -> bool { target .as_any() .downcast_ref::() .is_some_and(|target| { // prolly good self.is_empty() || (!target.is_empty() && self.0 >= target.0 && self.1 <= target.1) }) } fn subtypes(&self, acc: &mut Type) { acc.add(Arc::new(Clone::clone(self))) } fn as_any(&self) -> &dyn std::any::Any { self } fn mut_any(&mut self) -> &mut dyn std::any::Any { self } fn to_any(self) -> Box { Box::new(self) } } impl RangeT { pub fn is_empty(&self) -> bool { self.1 < self.0 } } struct RangeInt(isize, isize, bool); impl Iterator for RangeInt { type Item = isize; fn next(&mut self) -> Option { if !self.2 { let o = self.0; if self.0 < self.1 { self.0 += 1; } else { self.2 = true; } Some(o) } else { None } } }