From f1fefbc560454517f1f090c71ecd8ef52ae5d177 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 4 Aug 2024 12:25:01 +0200 Subject: [PATCH 01/49] wip --- src/object/list.rs | 25 ++++++----- src/object/vector/core.rs | 19 +++------ src/object/vector/rep.rs | 80 ++++++++++++++++++++++++++--------- src/object/vector/reptype.rs | 81 +++++++++++++++++++++++++++++------- 4 files changed, 146 insertions(+), 59 deletions(-) diff --git a/src/object/list.rs b/src/object/list.rs index 4d8a299a..61bdc525 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -2,22 +2,26 @@ use hashbrown::HashMap; use crate::error::Error; use crate::lang::EvalResult; +use crate::object::vector::rep::Rep; use super::*; type ListNameMap = HashMap>; +struct ListVals(Rep); + #[derive(Debug, Clone, PartialEq, Default)] pub struct List { pub names: CowObj, - pub values: CowObj, Obj)>>, - pub subsets: Subsets, + pub values: Rep<(Option, Obj)>, + // pub values: CowObj, Obj)>>, + // pub subsets: Subsets, } impl From, Obj)>> for List { fn from(value: Vec<(Option, Obj)>) -> Self { let mut result = List { - values: CowObj::from(value), + values: Rep::from(value), ..Default::default() }; @@ -31,7 +35,7 @@ impl List { self.names.with_inner_mut(|names| { names.drain(); - for (i, (k, _)) in self.values.borrow().iter().enumerate() { + for (i, (k, _)) in self.values.iter().enumerate() { if let Some(name) = k { let indices = names.entry(name.clone()).or_default(); if !indices.contains(&i) { @@ -43,12 +47,9 @@ impl List { } pub fn subset(&self, by: Subset) -> List { - let Subsets(mut inner) = self.subsets.clone(); - inner.push(by); List { names: self.names.clone(), - values: self.values.view_mut(), - subsets: Subsets(inner), + values: self.values.subset(by), } } @@ -210,6 +211,8 @@ impl List { match index.as_vector()? { Obj::Vector(v) if v.len() == 1 => { + self.values.subset(v.try_into()?); + self.values.get_inner(i) let Subsets(mut subsets) = self.subsets.clone(); subsets.push(v.try_into()?); @@ -265,11 +268,7 @@ impl List { } pub fn len(&self) -> usize { - let Subsets(inner) = &self.subsets; - match inner.as_slice() { - [] => self.values.borrow().len(), - [.., last] => std::cmp::min(self.values.borrow().len(), last.len()), - } + self.values.len() } #[must_use] diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 8e9b25d2..18eeb539 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -54,7 +54,12 @@ pub enum Vector { impl Clone for Vector { fn clone(&self) -> Self { - self.lazy_copy() + match self { + Vector::Double(v) => Vector::Double(v.clone()), + Vector::Character(v) => Vector::Character(v.clone()), + Vector::Integer(v) => Vector::Integer(v.clone()), + Vector::Logical(v) => Vector::Logical(v.clone()), + } } } @@ -69,18 +74,6 @@ impl Vector { } } - /// Create a lazy copy of the vector. - /// When mutating vectors, the internal data only needs to be copied when there is more than - /// one such lazy copy. - pub fn lazy_copy(&self) -> Self { - match self { - Vector::Double(v) => Vector::Double(v.clone()), - Vector::Character(v) => Vector::Character(v.clone()), - Vector::Integer(v) => Vector::Integer(v.clone()), - Vector::Logical(v) => Vector::Logical(v.clone()), - } - } - pub fn try_get(&self, index: Obj) -> EvalResult { let err = Error::Other("Vector index cannot be coerced into a valid indexing type.".to_string()); diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 7ce94f9c..5d60ef21 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -8,8 +8,7 @@ use super::reptype::RepTypeIter; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::object::CowObj; -use crate::object::ViewMut; +use crate::object::{CowObj, Obj, ViewMut}; /// Vector Representation /// @@ -18,7 +17,7 @@ use crate::object::ViewMut; #[derive(Debug, PartialEq)] pub struct Rep(pub RefCell>); -impl Clone for Rep { +impl Clone for Rep { fn clone(&self) -> Self { match self.borrow().clone() { RepType::Subset(v, s) => Rep(RefCell::new(RepType::Subset(v.clone(), s.clone()))), @@ -26,17 +25,23 @@ impl Clone for Rep { } } -impl ViewMut for Rep { +impl ViewMut for Rep { fn view_mut(&self) -> Self { Self(RefCell::new(self.borrow().view_mut())) } } +impl Rep { + pub fn try_get_inner_mut(&self, index: T) -> Result { + todo!() + } +} + impl Rep where - T: AtomicMode + Clone + Default, + T: Clone + Default, { - fn borrow(&self) -> Ref> { + pub fn borrow(&self) -> Ref> { self.0.borrow() } fn materialize_inplace(&self) -> &Self { @@ -47,6 +52,17 @@ where self } + /// Try to get mutable access to the internal vector through the passed closure. + /// This requires the vector to be in materialized form, otherwise None is returned. + /// None is returned if this is not the case. + pub fn with_inner_mut(&self, f: F) -> R + where + F: FnOnce(&mut Vec) -> R, + { + self.materialize_inplace(); + self.0.borrow().try_with_inner_mut(f).unwrap() + } + pub fn materialize(&self) -> Self { self.borrow().materialize().into() } @@ -101,6 +117,10 @@ where x.map(|x| x.into()) } + pub fn get_inner(&self, index: usize) -> Option { + self.borrow().get_inner(index) + } + pub fn assign(&mut self, value: Self) -> Self { self.0.borrow_mut().assign(value.0.into_inner()).into() } @@ -109,19 +129,31 @@ where /// Internally, this is defined by the [crate::object::coercion::AtomicMode] /// implementation of the vector's element type. /// - pub fn is_double(&self) -> bool { + pub fn is_double(&self) -> bool + where + T: AtomicMode, + { T::is_double() } /// See [Self::is_double] for more information - pub fn is_logical(&self) -> bool { + pub fn is_logical(&self) -> bool + where + T: AtomicMode, + { T::is_logical() } /// See [Self::is_double] for more information - pub fn is_integer(&self) -> bool { + pub fn is_integer(&self) -> bool + where + T: AtomicMode, + { T::is_integer() } /// See [Self::is_double] for more information - pub fn is_character(&self) -> bool { + pub fn is_character(&self) -> bool + where + T: AtomicMode, + { T::is_character() } @@ -151,7 +183,7 @@ where /// pub fn as_mode(&self) -> Rep where - T: CoercibleInto, + T: CoercibleInto + AtomicMode, Mode: Clone, { Rep(RefCell::new(self.borrow().as_mode())) @@ -160,7 +192,7 @@ where /// See [Self::as_mode] for more information pub fn as_logical(&self) -> Rep where - T: CoercibleInto, + T: CoercibleInto + AtomicMode, { self.as_mode::() } @@ -168,7 +200,7 @@ where /// See [Self::as_mode] for more information pub fn as_integer(&self) -> Rep where - T: CoercibleInto, + T: CoercibleInto + AtomicMode, { self.as_mode::() } @@ -176,7 +208,7 @@ where /// See [Self::as_mode] for more information pub fn as_double(&self) -> Rep where - T: CoercibleInto, + T: CoercibleInto + AtomicMode, { self.as_mode::() } @@ -184,7 +216,7 @@ where /// See [Self::as_mode] for more information pub fn as_character(&self) -> Rep where - T: CoercibleInto, + T: CoercibleInto + AtomicMode, { self.as_mode::() } @@ -213,11 +245,15 @@ where fn get_inner(&self, index: usize) -> Option { self.borrow().get_inner(index) } + + pub fn iter(&self) -> RepIter { + self.clone().into_iter() + } } impl Default for Rep where - T: AtomicMode + Clone + Default, + T: Clone + Default, { fn default() -> Self { Rep(RefCell::new(RepType::default())) @@ -228,7 +264,7 @@ pub struct RepIter(RepTypeIter); impl IntoIterator for Rep where - T: AtomicMode + Clone + Default, + T: Clone + Default, { type Item = T; type IntoIter = RepIter; @@ -240,7 +276,7 @@ where impl Iterator for RepIter where - T: AtomicMode + Clone + Default, + T: Clone + Default, { type Item = T; fn next(&mut self) -> Option { @@ -250,7 +286,7 @@ where impl From> for Rep where - T: AtomicMode + Clone + Default, + T: Clone + Default, { fn from(rep: RepType) -> Self { Rep(RefCell::new(rep)) @@ -273,6 +309,12 @@ where } } +impl From, Obj)>> for Rep<(Option, Obj)> { + fn from(value: Vec<(Option, Obj)>) -> Self { + Rep(RefCell::new(value.into())) + } +} + impl From>> for Rep { fn from(value: Vec>) -> Self { Rep(RefCell::new(value.into())) diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 74c5f607..4f498732 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -6,7 +6,9 @@ use super::subset::Subset; use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::object::{CowObj, ViewMut}; +use crate::error::Error; +use crate::internal_err; +use crate::object::{CowObj, Obj, ViewMut}; /// Vector #[derive(Debug, PartialEq)] @@ -25,15 +27,27 @@ impl Clone for RepType { } } -impl Default for RepType { +impl Default for RepType { fn default() -> Self { Self::new() } } +impl RepType { + pub fn get_inner_mut(&self, index: usize) -> Option { + match self { + RepType::Subset(v, subsets) => { + let vb = v.borrow(); + let index = subsets.get_index_at(index).unwrap(); + vb.get(index).map(|i| i.view_mut()) + } + } + } +} + impl IntoIterator for RepType where - T: AtomicMode + Clone + Default, + T: Clone + Default, { type Item = T; type IntoIter = RepTypeIter; @@ -50,13 +64,13 @@ pub enum RepTypeIter { SubsetIter(RepType, usize, usize), } -impl Iterator for RepTypeIter { +impl Iterator for RepTypeIter { type Item = T; fn next(&mut self) -> Option { match self { RepTypeIter::SubsetIter(rep, i, len) => { if i < len { - let x = Some(rep.get_atom(*i)); + let x = rep.get_inner(*i); *i += 1; x } else { @@ -75,7 +89,7 @@ impl ViewMut for RepType { } } -impl RepType { +impl RepType { /// Create an empty vector /// /// The primary use case for this function is to support testing, and there @@ -105,6 +119,21 @@ impl RepType { } } + /// Try to get mutable access to the internal vector through the passed closure. + /// This requires the vector to be in materialized form, otherwise None is returned. + /// None is returned if this is not the case. + pub fn try_with_inner_mut(&self, f: F) -> Result + where + F: FnOnce(&mut Vec) -> R, + { + match self { + RepType::Subset(v, Subsets(s)) => match s.as_slice() { + [] => Ok(v.with_inner_mut(f)), + _ => Err(internal_err!()), + }, + } + } + /// Subsetting a Vector /// /// Introduce a new subset into the aggregate list of subset indices. @@ -127,7 +156,6 @@ impl RepType { }, } } - #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 @@ -151,12 +179,12 @@ impl RepType { } } - pub fn get_atom(&self, index: usize) -> T { + pub fn get_inner(&self, index: usize) -> Option { match self { RepType::Subset(v, subsets) => { let vb = v.borrow(); let index = subsets.get_index_at(index).unwrap(); - vb[index].clone() + vb.get(index).cloned() } } } @@ -197,13 +225,20 @@ impl RepType { /// Materialize a Vector /// /// Apply subsets and clone values into a new vector. - /// pub fn materialize(&self) -> Self where T: Clone, { match self { RepType::Subset(v, subsets) => { + // early exit when there is nothing to do + match subsets { + Subsets(s) => match s.as_slice() { + [] => return self.clone(), + _ => (), + }, + } + let vc = v.clone(); let vb = vc.borrow(); let mut res: Vec = vec![]; @@ -222,19 +257,31 @@ impl RepType { } } - pub fn is_double(&self) -> bool { + pub fn is_double(&self) -> bool + where + T: AtomicMode, + { T::is_double() } - pub fn is_logical(&self) -> bool { + pub fn is_logical(&self) -> bool + where + T: AtomicMode, + { T::is_logical() } - pub fn is_integer(&self) -> bool { + pub fn is_integer(&self) -> bool + where + T: AtomicMode, + { T::is_integer() } - pub fn is_character(&self) -> bool { + pub fn is_character(&self) -> bool + where + T: AtomicMode, + { T::is_character() } @@ -334,6 +381,12 @@ where } } +impl From, Obj)>> for RepType<(Option, Obj)> { + fn from(value: Vec<(Option, Obj)>) -> Self { + RepType::Subset(value.into(), Subsets::default()) + } +} + impl From>> for RepType { fn from(value: Vec>) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); From 4011ab1b93786f057a0d5297c963cba5405bd947 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 5 Aug 2024 10:46:13 +0200 Subject: [PATCH 02/49] it compiles again, yeah --- src/callable/core.rs | 2 +- src/callable/primitive/c.rs | 2 - src/callable/primitive/names.rs | 1 - src/context/core.rs | 17 ++--- src/lang.rs | 21 +++--- src/object/core.rs | 6 +- src/object/environment.rs | 2 +- src/object/list.rs | 112 +++++++++++--------------------- src/object/vector/rep.rs | 13 +--- src/object/vector/reptype.rs | 18 +---- 10 files changed, 67 insertions(+), 127 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index e812723e..769b3a3c 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -47,7 +47,7 @@ pub trait Callable { 'inner: { // check argname with immutable borrow, but drop scope. If // found, drop borrow so we can mutably assign it - if let (Some(argname), _) = &args.values.borrow()[i] { + if let (Some(argname), _) = &args.values.get_inner(i).unwrap() { if let Some((Some(_), _)) = formals.remove_named(argname) { break 'inner; } diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index c79490ce..a6ad91e7 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -53,7 +53,6 @@ impl Callable for PrimitiveC { // lets first see what we're aiming to build. let ty: u8 = vals .values - .borrow() .iter() .map(|(_, v)| match v { Obj::Null => 0, @@ -76,7 +75,6 @@ impl Callable for PrimitiveC { // otherwise, try to collapse vectors into same type let ret = vals .values - .borrow() .iter() .map(|(_, r)| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index ac809071..67348b38 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -68,7 +68,6 @@ impl Callable for PrimitiveNames { Function(..) => Ok(Null), // return formals? List(x) => { Ok(x.values - .borrow() .iter() .map(|(k, _)| match k { Some(name) => OptionNA::Some(name.clone()), diff --git a/src/context/core.rs b/src/context/core.rs index edb1b616..ae425baa 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use crate::lang::{EvalResult, Signal}; +use crate::object::rep::Rep; use crate::object::*; use crate::{error::*, internal_err}; @@ -77,7 +78,7 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { Ok(ellipsis.values.into_iter()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(Rep::from(vec![]).into_iter()) } } (_, Expr::Ellipsis(Some(name))) => { @@ -89,8 +90,8 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { } // Avoid creating a new closure just to point to another, just reuse it (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { - Ok(c @ Obj::Promise(..)) => Ok(CowObj::from(vec![(k, c)]).into_iter()), - _ => Ok(CowObj::from(vec![( + Ok(c @ Obj::Promise(..)) => Ok(Rep::from(vec![(k, c)]).into_iter()), + _ => Ok(Rep::from(vec![( k, Obj::Promise(None, Expr::Symbol(s), self.env()), )]) @@ -98,11 +99,11 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { }, (k, c @ Expr::Call(..)) => { let elem = vec![(k, Obj::Promise(None, c, self.env()))]; - Ok(CowObj::from(elem).into_iter()) + Ok(Rep::from(elem).into_iter()) } (k, v) => { if let Ok(elem) = self.eval(v) { - Ok(CowObj::from(vec![(k, elem)]).into_iter()) + Ok(Rep::from(vec![(k, elem)]).into_iter()) } else { internal_err!() } @@ -123,18 +124,18 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { Ok(ellipsis.values.into_iter()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(Rep::from(vec![]).into_iter()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { Ok(more.values.into_iter()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(Rep::from(vec![]).into_iter()) } } (k, v) => match self.eval_and_finalize(v) { - Ok(elem) => Ok(CowObj::from(vec![(k, elem)]).into_iter()), + Ok(elem) => Ok(Rep::from(vec![(k, elem)]).into_iter()), Err(e) => Err(e), }, }) diff --git a/src/lang.rs b/src/lang.rs index c215b499..6c999d5c 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -3,12 +3,13 @@ use crate::cli::Experiment; use crate::context::Context; use crate::error::*; use crate::internal_err; +use crate::object::reptype::RepType; use crate::object::types::*; use crate::object::*; use crate::parser::LocalizedParser; use crate::parser::ParseResult; use crate::session::{Session, SessionParserConfig}; -use std::collections::HashSet; +use hashbrown::HashSet; use core::fmt; use std::fmt::Display; @@ -69,14 +70,9 @@ impl ViewMut for Obj { Vector::Logical(v) => Vector::Logical(v.view_mut()), }), - Obj::List(List { - names, - values, - subsets, - }) => Obj::List(List { + Obj::List(List { names, values }) => Obj::List(List { names: (*names).view_mut(), values: (*values).view_mut(), - subsets: (*subsets).clone(), }), // FIXME: this needs to be implemented for all objects that can be mutated x => x.clone(), @@ -217,7 +213,7 @@ impl Obj { match self { Obj::Vector(v) => v.get(index).map(Obj::Vector), Obj::Null => None, - Obj::List(l) => l.values.borrow().get(index).map(|x| x.1.clone()), + Obj::List(l) => l.values.get_inner(index).map(|x| x.1.clone()), Obj::Expr(..) => None, Obj::Promise(..) => None, Obj::Function(..) => None, @@ -229,7 +225,6 @@ impl Obj { match self { Obj::List(v) => v .values - .borrow() .iter() .find(|(k, _)| *k == Some(String::from(name))) .map(|(_, v)| v.clone()), @@ -376,7 +371,9 @@ impl Display for Obj { fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt::Result { let v = x.values.borrow(); - let s = x.subsets.clone(); + let s = match &*x.values.borrow() { + RepType::Subset(_, s) => s.clone(), + }; for (i, (_, si)) in s .bind_names(x.names.clone()) @@ -388,7 +385,7 @@ fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt let value; if let Some(i) = si { - (name, value) = v[i].clone(); + (name, value) = v.get_inner(i).unwrap().clone(); } else { return write!(f, "{}", Obj::Null); } @@ -1170,7 +1167,7 @@ pub fn assert_formals(session: &Session, formals: ExprList) -> Result true, (Obj::List(l), Obj::List(r)) => { - let lb = l.values.borrow(); - let rb = r.values.borrow(); - let liter = lb.iter(); - let riter = rb.iter(); + let liter = l.values.iter(); + let riter = r.values.iter(); liter .zip(riter) .all(|((lk, lv), (rk, rv))| lk == rk && lv == rv) diff --git a/src/object/environment.rs b/src/object/environment.rs index 7342b966..232d79ba 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -55,7 +55,7 @@ impl Environment { } pub fn append(&self, l: List) { - for (key, value) in l.values.borrow().iter() { + for (key, value) in l.values.iter() { if let Some(name) = key { self.values.borrow_mut().insert(name.clone(), value.clone()); } diff --git a/src/object/list.rs b/src/object/list.rs index 61bdc525..a2d25256 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,7 +1,9 @@ -use hashbrown::HashMap; +use hashbrown::{HashMap, HashSet}; +use std::borrow::Borrow; use crate::error::Error; use crate::lang::EvalResult; +use crate::object::reptype::RepType; use crate::object::vector::rep::Rep; use super::*; @@ -54,52 +56,44 @@ impl List { } pub fn assign(&mut self, value: Obj) -> EvalResult { + let subsets = match &*self.values.borrow() { + RepType::Subset(_, s) => s.clone(), + }; + let n = self.values.len(); + let iter = subsets + .clone() + .bind_names(self.names.clone()) + .into_iter() + .take(n); + match value { // remove elements from list Obj::Null => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - + let indices: HashSet = iter.map(|(i, _)| i).collect(); self.values.with_inner_mut(|values| { - for (i, _) in indices { - values.remove(i); - } + let mut i = 0; + values.retain(|_| { + let retain = !indices.contains(&i); + i += 1; + retain + }); }); self.reindex(); // TODO(feat): need to return list with NULL elements when // index is NA - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) } // any single length R value any if any.len() == Some(1) => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = self - .subsets + if let Some(max) = subsets .clone() .bind_names(self.names.clone()) .into_iter() + .take(n) .map(|(i, _)| i) .max() { @@ -107,37 +101,23 @@ impl List { } // then assign to indices - for (_, i) in indices { + for (_, i) in iter { if let Some(i) = i { v[i].1 = any.clone() } } }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) } // vectorized assignment // TODO(feature): warn when index recycling does not cycle evenly any if any.len() == Some(self.len()) => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = self - .subsets + if let Some(max) = subsets .clone() .bind_names(self.names.clone()) .into_iter() + .take(n) .map(|(i, _)| i) .max() { @@ -145,35 +125,21 @@ impl List { } // then assign to indices - for (any_i, (_, i)) in indices.enumerate() { + for (any_i, (_, i)) in iter.enumerate() { if let (Some(value), Some(i)) = (any.get(any_i), i) { v[i].1 = value; } } }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) } other => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = self - .subsets + if let Some(max) = subsets .clone() .bind_names(self.names.clone()) .into_iter() + .take(n) .map(|(i, _)| i) .max() { @@ -181,20 +147,18 @@ impl List { } // then assign to indices - for (_, i) in indices { + for (_, i) in iter { if let Some(i) = i { v[i].1 = other.clone() } } }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) } - } + }; + Ok(Obj::List(List { + names: self.names.clone(), + values: self.values.clone(), + })) } pub fn try_get(&self, index: Obj) -> EvalResult { @@ -212,9 +176,11 @@ impl List { match index.as_vector()? { Obj::Vector(v) if v.len() == 1 => { self.values.subset(v.try_into()?); - self.values.get_inner(i) - let Subsets(mut subsets) = self.subsets.clone(); - subsets.push(v.try_into()?); + // self.values.get_inner(i) + + let subsets = match &*self.values.borrow() { + RepType::Subset(_, Subsets(v)) => v.clone(), + }; if let Some((i, _)) = Subsets(subsets) .bind_names(self.names.clone()) diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 5d60ef21..648907fb 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -32,8 +32,8 @@ impl ViewMut for Rep { } impl Rep { - pub fn try_get_inner_mut(&self, index: T) -> Result { - todo!() + pub fn get_inner_mut(&self, index: usize) -> Option { + self.0.borrow().get_inner_mut(index) } } @@ -53,14 +53,11 @@ where } /// Try to get mutable access to the internal vector through the passed closure. - /// This requires the vector to be in materialized form, otherwise None is returned. - /// None is returned if this is not the case. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut Vec) -> R, { - self.materialize_inplace(); - self.0.borrow().try_with_inner_mut(f).unwrap() + self.0.borrow().with_inner_mut(f) } pub fn materialize(&self) -> Self { @@ -242,10 +239,6 @@ where .vectorized_partial_cmp(other.0.into_inner()) } - fn get_inner(&self, index: usize) -> Option { - self.borrow().get_inner(index) - } - pub fn iter(&self) -> RepIter { self.clone().into_iter() } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 4f498732..c93927b4 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -34,6 +34,7 @@ impl Default for RepType { } impl RepType { + /// Retrieve the internal data as a mutable view. pub fn get_inner_mut(&self, index: usize) -> Option { match self { RepType::Subset(v, subsets) => { @@ -122,15 +123,12 @@ impl RepType { /// Try to get mutable access to the internal vector through the passed closure. /// This requires the vector to be in materialized form, otherwise None is returned. /// None is returned if this is not the case. - pub fn try_with_inner_mut(&self, f: F) -> Result + pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut Vec) -> R, { match self { - RepType::Subset(v, Subsets(s)) => match s.as_slice() { - [] => Ok(v.with_inner_mut(f)), - _ => Err(internal_err!()), - }, + RepType::Subset(v, Subsets(s)) => v.with_inner_mut(f), } } @@ -179,16 +177,6 @@ impl RepType { } } - pub fn get_inner(&self, index: usize) -> Option { - match self { - RepType::Subset(v, subsets) => { - let vb = v.borrow(); - let index = subsets.get_index_at(index).unwrap(); - vb.get(index).cloned() - } - } - } - /// Assignment to Subset Indices /// /// Assignment to a vector from another. The aggregate subsetted indices From fca82a63c8c3f06535b3bfb5ddd4bf8641f44fcb Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 5 Aug 2024 11:01:04 +0200 Subject: [PATCH 03/49] two down --- src/object/list.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/object/list.rs b/src/object/list.rs index a2d25256..6ca1347d 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,5 +1,4 @@ use hashbrown::{HashMap, HashSet}; -use std::borrow::Borrow; use crate::error::Error; use crate::lang::EvalResult; @@ -10,14 +9,10 @@ use super::*; type ListNameMap = HashMap>; -struct ListVals(Rep); - #[derive(Debug, Clone, PartialEq, Default)] pub struct List { pub names: CowObj, pub values: Rep<(Option, Obj)>, - // pub values: CowObj, Obj)>>, - // pub subsets: Subsets, } impl From, Obj)>> for List { @@ -49,9 +44,11 @@ impl List { } pub fn subset(&self, by: Subset) -> List { + let values = self.values.view_mut(); + values.subset(by); List { names: self.names.clone(), - values: self.values.subset(by), + values, } } From 0f9743559b0677e6a40ce0ec819668f16812d70d Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 5 Aug 2024 11:37:25 +0200 Subject: [PATCH 04/49] another 3 down --- src/object/list.rs | 5 +++-- src/object/vector/reptype.rs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/object/list.rs b/src/object/list.rs index 6ca1347d..977c8adb 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -159,6 +159,7 @@ impl List { } pub fn try_get(&self, index: Obj) -> EvalResult { + println!("HIIIII"); let err = Error::Other("Cannot use object for indexing".to_string()); match index.as_vector()? { Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), @@ -172,10 +173,10 @@ impl List { match index.as_vector()? { Obj::Vector(v) if v.len() == 1 => { - self.values.subset(v.try_into()?); + let values = self.values.subset(v.try_into()?); // self.values.get_inner(i) - let subsets = match &*self.values.borrow() { + let subsets = match &*values.borrow() { RepType::Subset(_, Subsets(v)) => v.clone(), }; diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c93927b4..4dfa44b9 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -150,7 +150,8 @@ impl RepType { match self { RepType::Subset(v, Subsets(s)) => match s.as_slice() { [] => v.borrow().len(), - _ => unimplemented!(), + // FIXME: This can be wrong + [.., last] => std::cmp::min(v.len(), last.len()), }, } } From 10304f49cc5db52a86a9335fce4f4523120d94f6 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 5 Aug 2024 17:22:28 +0200 Subject: [PATCH 05/49] ... --- src/object/list.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/list.rs b/src/object/list.rs index 977c8adb..821f535c 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -44,8 +44,8 @@ impl List { } pub fn subset(&self, by: Subset) -> List { - let values = self.values.view_mut(); - values.subset(by); + println!("subsettt"); + let values = self.values.view_mut().subset(by); List { names: self.names.clone(), values, From 1df86076d0e7c83e178bae69ea4b2a5bdfa1d0ea Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 21 Sep 2024 16:40:31 +0530 Subject: [PATCH 06/49] cleanup --- src/callable/core.rs | 2 +- src/context/core.rs | 17 +++-- src/lang.rs | 16 +++-- src/object/list.rs | 133 ++++++++++++++++++++++------------- src/object/vector/reptype.rs | 7 +- 5 files changed, 104 insertions(+), 71 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 769b3a3c..e812723e 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -47,7 +47,7 @@ pub trait Callable { 'inner: { // check argname with immutable borrow, but drop scope. If // found, drop borrow so we can mutably assign it - if let (Some(argname), _) = &args.values.get_inner(i).unwrap() { + if let (Some(argname), _) = &args.values.borrow()[i] { if let Some((Some(_), _)) = formals.remove_named(argname) { break 'inner; } diff --git a/src/context/core.rs b/src/context/core.rs index ae425baa..edb1b616 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -1,7 +1,6 @@ use std::rc::Rc; use crate::lang::{EvalResult, Signal}; -use crate::object::rep::Rep; use crate::object::*; use crate::{error::*, internal_err}; @@ -78,7 +77,7 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { Ok(ellipsis.values.into_iter()) } else { - Ok(Rep::from(vec![]).into_iter()) + Ok(CowObj::from(vec![]).into_iter()) } } (_, Expr::Ellipsis(Some(name))) => { @@ -90,8 +89,8 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { } // Avoid creating a new closure just to point to another, just reuse it (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { - Ok(c @ Obj::Promise(..)) => Ok(Rep::from(vec![(k, c)]).into_iter()), - _ => Ok(Rep::from(vec![( + Ok(c @ Obj::Promise(..)) => Ok(CowObj::from(vec![(k, c)]).into_iter()), + _ => Ok(CowObj::from(vec![( k, Obj::Promise(None, Expr::Symbol(s), self.env()), )]) @@ -99,11 +98,11 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { }, (k, c @ Expr::Call(..)) => { let elem = vec![(k, Obj::Promise(None, c, self.env()))]; - Ok(Rep::from(elem).into_iter()) + Ok(CowObj::from(elem).into_iter()) } (k, v) => { if let Ok(elem) = self.eval(v) { - Ok(Rep::from(vec![(k, elem)]).into_iter()) + Ok(CowObj::from(vec![(k, elem)]).into_iter()) } else { internal_err!() } @@ -124,18 +123,18 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { Ok(ellipsis.values.into_iter()) } else { - Ok(Rep::from(vec![]).into_iter()) + Ok(CowObj::from(vec![]).into_iter()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { Ok(more.values.into_iter()) } else { - Ok(Rep::from(vec![]).into_iter()) + Ok(CowObj::from(vec![]).into_iter()) } } (k, v) => match self.eval_and_finalize(v) { - Ok(elem) => Ok(Rep::from(vec![(k, elem)]).into_iter()), + Ok(elem) => Ok(CowObj::from(vec![(k, elem)]).into_iter()), Err(e) => Err(e), }, }) diff --git a/src/lang.rs b/src/lang.rs index 6c999d5c..3262aa69 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -3,7 +3,6 @@ use crate::cli::Experiment; use crate::context::Context; use crate::error::*; use crate::internal_err; -use crate::object::reptype::RepType; use crate::object::types::*; use crate::object::*; use crate::parser::LocalizedParser; @@ -70,9 +69,14 @@ impl ViewMut for Obj { Vector::Logical(v) => Vector::Logical(v.view_mut()), }), - Obj::List(List { names, values }) => Obj::List(List { + Obj::List(List { + names, + values, + subsets, + }) => Obj::List(List { names: (*names).view_mut(), values: (*values).view_mut(), + subsets: (*subsets).clone(), }), // FIXME: this needs to be implemented for all objects that can be mutated x => x.clone(), @@ -213,7 +217,7 @@ impl Obj { match self { Obj::Vector(v) => v.get(index).map(Obj::Vector), Obj::Null => None, - Obj::List(l) => l.values.get_inner(index).map(|x| x.1.clone()), + Obj::List(l) => l.values.borrow().get(index).map(|x| x.1.clone()), Obj::Expr(..) => None, Obj::Promise(..) => None, Obj::Function(..) => None, @@ -371,9 +375,7 @@ impl Display for Obj { fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt::Result { let v = x.values.borrow(); - let s = match &*x.values.borrow() { - RepType::Subset(_, s) => s.clone(), - }; + let s = x.subsets.clone(); for (i, (_, si)) in s .bind_names(x.names.clone()) @@ -385,7 +387,7 @@ fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt let value; if let Some(i) = si { - (name, value) = v.get_inner(i).unwrap().clone(); + (name, value) = v[i].clone(); } else { return write!(f, "{}", Obj::Null); } diff --git a/src/object/list.rs b/src/object/list.rs index 821f535c..4d8a299a 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,9 +1,7 @@ -use hashbrown::{HashMap, HashSet}; +use hashbrown::HashMap; use crate::error::Error; use crate::lang::EvalResult; -use crate::object::reptype::RepType; -use crate::object::vector::rep::Rep; use super::*; @@ -12,13 +10,14 @@ type ListNameMap = HashMap>; #[derive(Debug, Clone, PartialEq, Default)] pub struct List { pub names: CowObj, - pub values: Rep<(Option, Obj)>, + pub values: CowObj, Obj)>>, + pub subsets: Subsets, } impl From, Obj)>> for List { fn from(value: Vec<(Option, Obj)>) -> Self { let mut result = List { - values: Rep::from(value), + values: CowObj::from(value), ..Default::default() }; @@ -32,7 +31,7 @@ impl List { self.names.with_inner_mut(|names| { names.drain(); - for (i, (k, _)) in self.values.iter().enumerate() { + for (i, (k, _)) in self.values.borrow().iter().enumerate() { if let Some(name) = k { let indices = names.entry(name.clone()).or_default(); if !indices.contains(&i) { @@ -44,53 +43,62 @@ impl List { } pub fn subset(&self, by: Subset) -> List { - println!("subsettt"); - let values = self.values.view_mut().subset(by); + let Subsets(mut inner) = self.subsets.clone(); + inner.push(by); List { names: self.names.clone(), - values, + values: self.values.view_mut(), + subsets: Subsets(inner), } } pub fn assign(&mut self, value: Obj) -> EvalResult { - let subsets = match &*self.values.borrow() { - RepType::Subset(_, s) => s.clone(), - }; - let n = self.values.len(); - let iter = subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - match value { // remove elements from list Obj::Null => { - let indices: HashSet = iter.map(|(i, _)| i).collect(); + let n = self.values.len(); + let indices = self + .subsets + .clone() + .bind_names(self.names.clone()) + .into_iter() + .take(n); + self.values.with_inner_mut(|values| { - let mut i = 0; - values.retain(|_| { - let retain = !indices.contains(&i); - i += 1; - retain - }); + for (i, _) in indices { + values.remove(i); + } }); self.reindex(); // TODO(feat): need to return list with NULL elements when // index is NA + + Ok(Obj::List(List { + names: self.names.clone(), + values: self.values.clone(), + subsets: self.subsets.clone(), + })) } // any single length R value any if any.len() == Some(1) => { + let n = self.values.len(); + let indices = self + .subsets + .clone() + .bind_names(self.names.clone()) + .into_iter() + .take(n); + self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = subsets + if let Some(max) = self + .subsets .clone() .bind_names(self.names.clone()) .into_iter() - .take(n) .map(|(i, _)| i) .max() { @@ -98,23 +106,37 @@ impl List { } // then assign to indices - for (_, i) in iter { + for (_, i) in indices { if let Some(i) = i { v[i].1 = any.clone() } } }); + + Ok(Obj::List(List { + names: self.names.clone(), + values: self.values.clone(), + subsets: self.subsets.clone(), + })) } // vectorized assignment // TODO(feature): warn when index recycling does not cycle evenly any if any.len() == Some(self.len()) => { + let n = self.values.len(); + let indices = self + .subsets + .clone() + .bind_names(self.names.clone()) + .into_iter() + .take(n); + self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = subsets + if let Some(max) = self + .subsets .clone() .bind_names(self.names.clone()) .into_iter() - .take(n) .map(|(i, _)| i) .max() { @@ -122,21 +144,35 @@ impl List { } // then assign to indices - for (any_i, (_, i)) in iter.enumerate() { + for (any_i, (_, i)) in indices.enumerate() { if let (Some(value), Some(i)) = (any.get(any_i), i) { v[i].1 = value; } } }); + + Ok(Obj::List(List { + names: self.names.clone(), + values: self.values.clone(), + subsets: self.subsets.clone(), + })) } other => { + let n = self.values.len(); + let indices = self + .subsets + .clone() + .bind_names(self.names.clone()) + .into_iter() + .take(n); + self.values.with_inner_mut(|v| { // first check to see if we need to extend - if let Some(max) = subsets + if let Some(max) = self + .subsets .clone() .bind_names(self.names.clone()) .into_iter() - .take(n) .map(|(i, _)| i) .max() { @@ -144,22 +180,23 @@ impl List { } // then assign to indices - for (_, i) in iter { + for (_, i) in indices { if let Some(i) = i { v[i].1 = other.clone() } } }); + + Ok(Obj::List(List { + names: self.names.clone(), + values: self.values.clone(), + subsets: self.subsets.clone(), + })) } - }; - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - })) + } } pub fn try_get(&self, index: Obj) -> EvalResult { - println!("HIIIII"); let err = Error::Other("Cannot use object for indexing".to_string()); match index.as_vector()? { Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), @@ -173,12 +210,8 @@ impl List { match index.as_vector()? { Obj::Vector(v) if v.len() == 1 => { - let values = self.values.subset(v.try_into()?); - // self.values.get_inner(i) - - let subsets = match &*values.borrow() { - RepType::Subset(_, Subsets(v)) => v.clone(), - }; + let Subsets(mut subsets) = self.subsets.clone(); + subsets.push(v.try_into()?); if let Some((i, _)) = Subsets(subsets) .bind_names(self.names.clone()) @@ -232,7 +265,11 @@ impl List { } pub fn len(&self) -> usize { - self.values.len() + let Subsets(inner) = &self.subsets; + match inner.as_slice() { + [] => self.values.borrow().len(), + [.., last] => std::cmp::min(self.values.borrow().len(), last.len()), + } } #[must_use] diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 4dfa44b9..8e6599d2 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -6,8 +6,6 @@ use super::subset::Subset; use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::error::Error; -use crate::internal_err; use crate::object::{CowObj, Obj, ViewMut}; /// Vector @@ -121,21 +119,18 @@ impl RepType { } /// Try to get mutable access to the internal vector through the passed closure. - /// This requires the vector to be in materialized form, otherwise None is returned. - /// None is returned if this is not the case. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut Vec) -> R, { match self { - RepType::Subset(v, Subsets(s)) => v.with_inner_mut(f), + RepType::Subset(v, _) => v.with_inner_mut(f), } } /// Subsetting a Vector /// /// Introduce a new subset into the aggregate list of subset indices. - /// pub fn subset(&self, subset: Subset) -> Self { match self { RepType::Subset(v, Subsets(subsets)) => { From cbe46c1f5dced5fbc77d61bc567f17131a11ee02 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 21 Sep 2024 16:46:22 +0530 Subject: [PATCH 07/49] gst --- src/object/vector/reptype.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 8e6599d2..c465a442 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -145,8 +145,7 @@ impl RepType { match self { RepType::Subset(v, Subsets(s)) => match s.as_slice() { [] => v.borrow().len(), - // FIXME: This can be wrong - [.., last] => std::cmp::min(v.len(), last.len()), + _ => unimplemented!(), }, } } From 65e4a5a2c37fbbe3ce038372ceeee76fa8229c3a Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 21 Sep 2024 17:22:12 +0530 Subject: [PATCH 08/49] silence clippy --- src/object/vector/reptype.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c465a442..d876045c 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -216,10 +216,11 @@ impl RepType { RepType::Subset(v, subsets) => { // early exit when there is nothing to do match subsets { - Subsets(s) => match s.as_slice() { - [] => return self.clone(), - _ => (), - }, + Subsets(s) => { + if s.as_slice().is_empty() { + return self.clone(); + } + } } let vc = v.clone(); From 80f0245524552b6c9397eabcbe5b2cf1cdda965b Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 22 Sep 2024 16:31:59 +0530 Subject: [PATCH 09/49] ... --- src/callable/primitive/c.rs | 70 +++++++++++++--- src/callable/primitive/names.rs | 7 +- src/object/vector/core.rs | 38 +++++++++ src/object/vector/rep.rs | 31 ++++++- src/object/vector/reptype.rs | 138 +++++++++++++++++++++++++------- src/object/vector/subsets.rs | 9 +++ 6 files changed, 249 insertions(+), 44 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index a6ad91e7..be1031c2 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -62,17 +62,62 @@ impl Callable for PrimitiveC { }) .fold(0, std::cmp::max); + // if the output will have names + let named = vals.values.borrow().iter().any(|(n, o)| { + if n.is_some() { + return true; + } + match o { + Obj::Vector(v) => v.has_names(), + Obj::List(l) => l.names.borrow().len() > 0, + _ => todo!(), + } + }); + // most complex type was NULL if ty == 0 { return Ok(Obj::Null); } // most complex type was List + // FIXME: handle names if ty == 2 { return Ok(Obj::List(vals)); } - // otherwise, try to collapse vectors into same type + let names: Option> = if named { + let nms = vals.values.iter().flat_map(|(name, obj)| { + let maybe_prefix = name.as_ref().and_then(|n| Option::Some(n.clone())); + + if let Obj::Vector(v) = obj { + let maybe_names_iter = v.iter_names(); + + let x: Vec = match (maybe_prefix, maybe_names_iter) { + (None, None) => std::iter::repeat(Character::NA).take(v.len()).collect(), + (Some(prefix), None) => std::iter::repeat(Character::Some(prefix.clone())) + .take(v.len()) + .collect(), + (None, Some(names_iter)) => names_iter.collect(), + (Some(prefix), Some(names_iter)) => names_iter + .map(|maybe_name| { + if let OptionNA::Some(name) = maybe_name { + Character::Some(format!("{}.{}", prefix, name)) + } else { + Character::Some(prefix.clone()) + } + }) + .collect(), + }; + x + } else { + unimplemented!() + } + }); + Some(nms.collect()) + } else { + None + }; + let ret = vals .values .iter() @@ -94,8 +139,8 @@ impl Callable for PrimitiveC { }); // consume values and merge into a new collection - match ret { - Vector::Character(_) => Ok(Obj::Vector(Vector::from( + let v = match ret { + Vector::Character(_) => Vector::from( Vec::>::new() .into_iter() .chain( @@ -107,8 +152,8 @@ impl Callable for PrimitiveC { }), ) .collect::>(), - ))), - Vector::Double(_) => Ok(Obj::Vector(Vector::from( + ), + Vector::Double(_) => Vector::from( Vec::>::new() .into_iter() .chain( @@ -120,8 +165,8 @@ impl Callable for PrimitiveC { }), ) .collect::>(), - ))), - Vector::Integer(_) => Ok(Obj::Vector(Vector::from( + ), + Vector::Integer(_) => Vector::from( Vec::>::new() .into_iter() .chain( @@ -133,8 +178,8 @@ impl Callable for PrimitiveC { }), ) .collect::>(), - ))), - Vector::Logical(_) => Ok(Obj::Vector(Vector::from( + ), + Vector::Logical(_) => Vector::from( Vec::>::new() .into_iter() .chain( @@ -146,7 +191,12 @@ impl Callable for PrimitiveC { }), ) .collect::>(), - ))), + ), + }; + + if let Some(names) = names { + v.set_names_(names.into()) } + Ok(Obj::Vector(v)) } } diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 67348b38..5324596f 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -63,8 +63,11 @@ impl Callable for PrimitiveNames { match x { Null => Ok(Null), Promise(..) => Ok(Null), - Vector(..) => Ok(Null), // named vectors currently not supported... - Expr(..) => Ok(Null), // handle arg lists? + Vector(v) => match v.names() { + Some(n) => Ok(Obj::Vector(n)), + None => Ok(Null), + }, + Expr(..) => Ok(Null), // handle arg lists? Function(..) => Ok(Null), // return formals? List(x) => { Ok(x.values diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 18eeb539..b6da6953 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -3,6 +3,7 @@ use std::fmt::Display; use crate::error::Error; use crate::lang::EvalResult; +use crate::object::CowObj; use crate::object::Obj; use super::coercion::CoercibleInto; @@ -74,6 +75,43 @@ impl Vector { } } + pub fn has_names(&self) -> bool { + self.iter_names().is_some() + } + + /// Iterate over the names of the vector. + pub fn iter_names(&self) -> Option>>> { + use Vector::*; + let names = match self { + Double(x) => x.names(), + Integer(x) => x.names(), + Logical(x) => x.names(), + Character(x) => x.names(), + }; + + if let Some(n) = names { + Some(Box::new(n.iter())) + } else { + None + } + } + + /// Get the names of the vector. + pub fn names(&self) -> Option { + let i = self.iter_names()?; + let x: Option = Some(i.collect::>>().into()); + x + } + + pub fn set_names_(&self, names: CowObj>) { + match self { + Vector::Character(x) => x.set_names_(names), + Vector::Logical(x) => x.set_names_(names), + Vector::Integer(x) => x.set_names_(names), + Vector::Double(x) => x.set_names_(names), + }; + } + pub fn try_get(&self, index: Obj) -> EvalResult { let err = Error::Other("Vector index cannot be coerced into a valid indexing type.".to_string()); diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 648907fb..2018c951 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -8,6 +8,8 @@ use super::reptype::RepTypeIter; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; +use crate::object::reptype::Naming; +use crate::object::vector::*; use crate::object::{CowObj, Obj, ViewMut}; /// Vector Representation @@ -20,7 +22,11 @@ pub struct Rep(pub RefCell>); impl Clone for Rep { fn clone(&self) -> Self { match self.borrow().clone() { - RepType::Subset(v, s) => Rep(RefCell::new(RepType::Subset(v.clone(), s.clone()))), + RepType::Subset(v, s, n) => Rep(RefCell::new(RepType::Subset( + v.clone(), + s.clone(), + n.clone(), + ))), } } } @@ -44,6 +50,7 @@ where pub fn borrow(&self) -> Ref> { self.0.borrow() } + fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily let new_repr = { self.borrow().materialize() }; @@ -52,6 +59,28 @@ where self } + /// + pub fn set_names_(&self, names: CowObj>>) { + let mut new_repr = self.borrow().materialize().set_names(names); + self.0.replace(new_repr); + } + + pub fn names(&self) -> Option>> { + match self.borrow().clone() { + RepType::Subset(_, s, n) => { + if s.is_empty() { + if let Option::Some(n) = n { + Option::Some(n.clone().names) + } else { + Option::None + } + } else { + unimplemented!() + } + } + } + } + /// Try to get mutable access to the internal vector through the passed closure. pub fn with_inner_mut(&self, f: F) -> R where diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index d876045c..c21f8958 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -7,12 +7,58 @@ use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::object::{CowObj, Obj, ViewMut}; +use hashbrown::HashMap; + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct Naming { + // TODO: change this to usize and not Vec (after making names unique) + pub map: CowObj>>, + pub names: CowObj>>, +} + +impl Naming { + pub fn new() -> Self { + Naming::default() + } + pub fn push_name(&self, name: OptionNA) { + self.names.with_inner_mut(|v| v.push(name.clone())); + if let OptionNA::Some(name) = name { + let n = self.names.len(); + self.map.with_inner_mut(|map| { + let indices = map.entry(name.clone()).or_default(); + if !indices.contains(&n) { + indices.push(n); + }; + }); + }; + } +} + +impl From>> for Naming { + fn from(value: CowObj>) -> Self { + let mut map: HashMap> = HashMap::new(); + + value.iter().enumerate().map(|(i, maybe_name)| { + if let OptionNA::Some(name) = maybe_name { + let indices = map.entry(name.clone()).or_default(); + if !indices.contains(&i) { + indices.push(i); + }; + }; + }); + + Self { + map: map.into(), + names: value, + } + } +} /// Vector #[derive(Debug, PartialEq)] pub enum RepType { // Vector::Subset encompasses a "raw" vector (no subsetting) - Subset(CowObj>, Subsets), + Subset(CowObj>, Subsets, Option), // Iterator includes things like ranges 1:Inf, and lazily computed values // Iter(Box>) } @@ -20,7 +66,8 @@ pub enum RepType { impl Clone for RepType { fn clone(&self) -> Self { match self { - RepType::Subset(v, s) => RepType::Subset(v.view_mut(), s.clone()), + // FIXME: should this reall call .view_mut()? should add comment + RepType::Subset(v, s, n) => RepType::Subset(v.view_mut(), s.clone(), n.clone()), } } } @@ -35,7 +82,7 @@ impl RepType { /// Retrieve the internal data as a mutable view. pub fn get_inner_mut(&self, index: usize) -> Option { match self { - RepType::Subset(v, subsets) => { + RepType::Subset(v, subsets, _) => { let vb = v.borrow(); let index = subsets.get_index_at(index).unwrap(); vb.get(index).map(|i| i.view_mut()) @@ -83,7 +130,7 @@ impl Iterator for RepTypeIter { impl ViewMut for RepType { fn view_mut(&self) -> Self { match self { - RepType::Subset(v, s) => RepType::Subset(v.view_mut(), s.clone()), + RepType::Subset(v, s, n) => RepType::Subset(v.view_mut(), s.clone(), n.clone()), } } } @@ -108,13 +155,21 @@ impl RepType { /// ``` /// pub fn new() -> Self { - RepType::Subset(Vec::new().into(), Subsets(Vec::new())) + RepType::Subset(Vec::new().into(), Subsets(Vec::new()), Option::None) + } + + pub fn set_names(&self, names: CowObj>) -> Self { + match self { + RepType::Subset(v, s, _) => { + RepType::Subset(v.clone(), s.clone(), Option::Some(names.into())) + } + } } /// Access a lazy copy of the internal vector data pub fn inner(&self) -> CowObj> { match self.materialize() { - RepType::Subset(v, _) => v.clone(), + RepType::Subset(v, ..) => v.clone(), } } @@ -124,7 +179,7 @@ impl RepType { F: FnOnce(&mut Vec) -> R, { match self { - RepType::Subset(v, _) => v.with_inner_mut(f), + RepType::Subset(v, ..) => v.with_inner_mut(f), } } @@ -133,17 +188,17 @@ impl RepType { /// Introduce a new subset into the aggregate list of subset indices. pub fn subset(&self, subset: Subset) -> Self { match self { - RepType::Subset(v, Subsets(subsets)) => { + RepType::Subset(v, Subsets(subsets), n) => { let mut subsets = subsets.clone(); subsets.push(subset); - RepType::Subset(v.view_mut(), Subsets(subsets)) + RepType::Subset(v.view_mut(), Subsets(subsets), n.clone()) } } } pub fn len(&self) -> usize { match self { - RepType::Subset(v, Subsets(s)) => match s.as_slice() { + RepType::Subset(v, Subsets(s), _) => match s.as_slice() { [] => v.borrow().len(), _ => unimplemented!(), }, @@ -163,11 +218,15 @@ impl RepType { T: Clone, { match self { - RepType::Subset(v, subsets) => { + RepType::Subset(v, subsets, _) => { let vb = v.borrow(); let index = subsets.get_index_at(index)?; let elem = vb.get(index)?; - Some(RepType::Subset(vec![elem.clone()].into(), Subsets::new())) + Some(RepType::Subset( + vec![elem.clone()].into(), + Subsets::new(), + Option::Some(Naming::new()), + )) } } } @@ -182,7 +241,7 @@ impl RepType { T: Clone + Default, { match (self, value) { - (RepType::Subset(lv, ls), RepType::Subset(rv, rs)) => { + (RepType::Subset(lv, ls, ln), RepType::Subset(rv, rs, _)) => { lv.with_inner_mut(|lvb| { let rvc = rv.clone(); let rvb = rvc.borrow(); @@ -200,7 +259,7 @@ impl RepType { } }); - RepType::Subset(lv.clone(), ls.clone()) + RepType::Subset(lv.clone(), ls.clone(), ln.clone()) } } } @@ -213,7 +272,7 @@ impl RepType { T: Clone, { match self { - RepType::Subset(v, subsets) => { + RepType::Subset(v, subsets, naming) => { // early exit when there is nothing to do match subsets { Subsets(s) => { @@ -228,15 +287,28 @@ impl RepType { let mut res: Vec = vec![]; let vb_len = vb.len(); + let new_naming = Naming::new(); + let iter = subsets.clone().into_iter().take_while(|(i, _)| i < &vb_len); + for (_, i) in iter { match i { - Some(i) => res.push(vb[i].clone()), - None => res.push(T::default()), + Some(i) => { + res.push(vb[i].clone()); + if let Option::Some(n) = naming { + new_naming.push_name(n.names.borrow()[i].clone()) + }; + } + // default is NA + None => { + res.push(T::default()); + // When we subset with NA, there is no name for this entry; + new_naming.push_name(OptionNA::NA); + } } } - RepType::Subset(res.into(), Subsets(vec![])) + RepType::Subset(res.into(), Subsets(vec![]), Option::None) } } } @@ -275,13 +347,13 @@ impl RepType { Mode: Clone, { match self { - RepType::Subset(v, subsets) => { + RepType::Subset(v, subsets, naming) => { let vc = v.clone(); let vb = vc.borrow(); let num_vec: Vec = vb.iter().map(|i| (*i).clone().coerce_into()).collect(); - RepType::Subset(num_vec.into(), subsets.clone()) + RepType::Subset(num_vec.into(), subsets.clone(), naming.clone()) } } } @@ -340,7 +412,10 @@ impl RepType { pub fn get_inner(&self, index: usize) -> Option { match self { - RepType::Subset(v, subsets) => { + RepType::Subset(v, subsets, n) => { + if n.is_some() { + unimplemented!() + } let vb = v.borrow(); let index = subsets.get_index_at(index)?; vb.get(index).cloned() @@ -367,63 +442,64 @@ where impl From, Obj)>> for RepType<(Option, Obj)> { fn from(value: Vec<(Option, Obj)>) -> Self { - RepType::Subset(value.into(), Subsets::default()) + // FIXME: How to handle names? + RepType::Subset(value.into(), Subsets::default(), Option::None) } } impl From>> for RepType { fn from(value: Vec>) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From> for RepType { fn from(value: Vec) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From>> for RepType { fn from(value: Vec>) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From> for RepType { fn from(value: Vec) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From>> for RepType { fn from(value: Vec>) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From> for RepType { fn from(value: Vec) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From>> for RepType { fn from(value: Vec>) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } impl From> for RepType { fn from(value: Vec) -> Self { let value: Vec<_> = value.into_iter().map(|i| i.coerce_into()).collect(); - RepType::Subset(value.into(), Subsets(Vec::new())) + RepType::Subset(value.into(), Subsets(Vec::new()), Option::None) } } @@ -434,7 +510,7 @@ where { fn from(value: (Vec, Subsets)) -> Self { match Self::from(value.0) { - RepType::Subset(v, _) => RepType::Subset(v, value.1), + RepType::Subset(v, ..) => RepType::Subset(v, value.1, Option::None), } } } diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index e7e06417..c6d2b4cc 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -32,6 +32,15 @@ impl Subsets { Some(index) } + pub fn len(&self) -> usize { + self.0.len() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn push(self, subset: T) where T: Into, From 377e029033b17b638a7fbba36b195b3118240ca6 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 23 Sep 2024 18:58:34 +0530 Subject: [PATCH 10/49] ... --- src/callable/primitive/c.rs | 2 +- src/callable/primitive/names.rs | 2 +- src/object/list.rs | 66 ++++++++++++++++++++++++++++ src/object/vector/core.rs | 47 ++++++++++++-------- src/object/vector/rep.rs | 78 +++++++++++++++++++++++++++++++-- src/object/vector/reptype.rs | 27 +++++++++++- 6 files changed, 198 insertions(+), 24 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index be1031c2..b89cf26d 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -68,7 +68,7 @@ impl Callable for PrimitiveC { return true; } match o { - Obj::Vector(v) => v.has_names(), + Obj::Vector(v) => v.names().is_none(), Obj::List(l) => l.names.borrow().len() > 0, _ => todo!(), } diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 5324596f..dc5e0606 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -64,7 +64,7 @@ impl Callable for PrimitiveNames { Null => Ok(Null), Promise(..) => Ok(Null), Vector(v) => match v.names() { - Some(n) => Ok(Obj::Vector(n)), + Some(n) => Ok(Obj::Vector(n.into())), None => Ok(Null), }, Expr(..) => Ok(Null), // handle arg lists? diff --git a/src/object/list.rs b/src/object/list.rs index 4d8a299a..5c1d634f 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -2,11 +2,77 @@ use hashbrown::HashMap; use crate::error::Error; use crate::lang::EvalResult; +use crate::object::rep::Rep; +use crate::object::vector::types::Character; use super::*; type ListNameMap = HashMap>; +struct List2(Rep); + +impl From> for List2 { + fn from(x: Rep) -> Self { + List2(x) + } +} + +impl List2 { + pub fn reindex(&mut self) { + self.0.reindex() + } + + pub fn assign(&mut self, other: Obj) -> EvalResult { + todo!() + } + + pub fn try_get(&self, index: Obj) -> EvalResult { + let err = Error::Other("Cannot use object for indexing".to_string()); + todo!() + // match index.as_vector()? { + // Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), + // _ => Err(err.into()), + // } + } + + pub fn try_get_inner(&self, index: Obj) -> EvalResult { + // #[allow(clippy::map_clone)] + // self.try_get_inner_mut(index).map(|v| v.clone()) + todo!() + } + + pub fn subset(&self, subset: Subset) -> Self { + self.0.subset(subset).into() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn materialize(self) -> Self { + List2::from(self.0.materialize()) + } + + pub fn assign(&mut self, other: Obj) -> EvalResult { + // TODO: Rep currently does not handle names. + todo!() + } + + /// Get the names of the vector. + pub fn names(&self) -> Option>> { + self.0.names() + } + + pub fn set_names_(&self, names: CowObj>) { + self.0.set_names_(names) + } +} + #[derive(Debug, Clone, PartialEq, Default)] pub struct List { pub names: CowObj, diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index b6da6953..d9135c26 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -75,34 +75,28 @@ impl Vector { } } - pub fn has_names(&self) -> bool { - self.iter_names().is_some() - } - /// Iterate over the names of the vector. pub fn iter_names(&self) -> Option>>> { use Vector::*; - let names = match self { + match self { + Double(x) => x.iter_names(), + Integer(x) => x.iter_names(), + Logical(x) => x.iter_names(), + Character(x) => x.iter_names(), + } + } + + /// Get the names of the vector. + pub fn names(&self) -> Option>> { + use Vector::*; + match self { Double(x) => x.names(), Integer(x) => x.names(), Logical(x) => x.names(), Character(x) => x.names(), - }; - - if let Some(n) = names { - Some(Box::new(n.iter())) - } else { - None } } - /// Get the names of the vector. - pub fn names(&self) -> Option { - let i = self.iter_names()?; - let x: Option = Some(i.collect::>>().into()); - x - } - pub fn set_names_(&self, names: CowObj>) { match self { Vector::Character(x) => x.set_names_(names), @@ -132,6 +126,17 @@ impl Vector { } } + pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { + // This method will be needed when we have scalars + todo!() + } + + pub fn try_get_inner(&self, index: Obj) -> EvalResult { + // This method will be needed when we have scalars + #[allow(clippy::map_clone)] + self.try_get_inner_mut(index).map(|v| v.clone()) + } + pub fn subset(&self, subset: Subset) -> Self { match self { Vector::Double(x) => x.subset(subset).into(), @@ -275,6 +280,12 @@ impl TryInto for Vector { } } +impl From>> for Vector { + fn from(x: CowObj>) -> Self { + Vector::Character(x.into()) + } +} + impl From> for Vector { fn from(x: RepType) -> Self { Vector::Double(x.into()) diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 2018c951..41a2ce53 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -1,4 +1,4 @@ -use std::cell::{Ref, RefCell}; +use std::cell::{Ref, RefCell, RefMut}; use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; @@ -41,6 +41,14 @@ impl Rep { pub fn get_inner_mut(&self, index: usize) -> Option { self.0.borrow().get_inner_mut(index) } + + pub fn try_get_inner_mut(&self, subset: Subset) -> Option { + + } + + pub fn try_get_inner(&self, subset: Subset) -> T { + + } } impl Rep @@ -51,6 +59,22 @@ where self.0.borrow() } + pub fn try_get(&self, subset: Subset) -> T { + + } + + pub fn iter_names(&self) -> Option>>> { + if let Some(names) = self.names() { + Some(Box::new(names.iter())) + } else { + None + } + } + + pub fn borrow_mut(&mut self) -> RefMut> { + self.0.borrow_mut() + } + fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily let new_repr = { self.borrow().materialize() }; @@ -59,9 +83,14 @@ where self } - /// + /// Reindex the mapping from names to indices. + pub fn reindex(&mut self) { + self.borrow_mut().reindex() + } + + /// Set the names of the vector. pub fn set_names_(&self, names: CowObj>>) { - let mut new_repr = self.borrow().materialize().set_names(names); + let new_repr = self.borrow().materialize().set_names(names); self.0.replace(new_repr); } @@ -81,6 +110,40 @@ where } } + pub fn dedup_last(self) -> Self { + todo!() + // Note: We need to ensure here that we duplicate the names and the values. + // Previously this was stored in one vector with tuples but now this is split up + if let RepType::Subset(values) + + self.names.with_inner_mut(|names| { + let mut dups: Vec = names + .iter() + .flat_map(|(_, indices)| { + indices + .split_last() + .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) + }) + .collect(); + + dups.sort(); + + self.values.with_inner_mut(|vs| { + for i in dups.into_iter().rev() { + vs.remove(i); + } + }); + }); + + self.names.with_inner_mut(|names| { + for (_, indices) in names.iter_mut() { + indices.drain(0..indices.len()); + } + }); + + self + } + /// Try to get mutable access to the internal vector through the passed closure. pub fn with_inner_mut(&self, f: F) -> R where @@ -306,6 +369,15 @@ where } } +impl From>> for Rep +where + T: Clone + Default, +{ + fn from(rep: CowObj>) -> Self { + Rep(RefCell::new(rep.into())) + } +} + impl From> for Rep where T: Clone + Default, diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c21f8958..59e8e523 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -158,6 +158,25 @@ impl RepType { RepType::Subset(Vec::new().into(), Subsets(Vec::new()), Option::None) } + /// Reindex the mapping from names to indices. + pub fn reindex(&mut self) { + match self { + RepType::Subset(.., Some(naming)) => naming.map.with_inner_mut(|map| { + map.drain(); + + for (i, maybe_name) in naming.names.borrow().iter().enumerate() { + if let OptionNA::Some(name) = maybe_name { + let indices = map.entry(name.clone()).or_default(); + if !indices.contains(&i) { + indices.push(i) + } + } + } + }), + _ => (), + } + } + pub fn set_names(&self, names: CowObj>) -> Self { match self { RepType::Subset(v, s, _) => { @@ -173,7 +192,7 @@ impl RepType { } } - /// Try to get mutable access to the internal vector through the passed closure. + /// Get mutable access to the internal vector through the passed closure. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut Vec) -> R, @@ -440,6 +459,12 @@ where } } +impl From>> for RepType { + fn from(value: CowObj>) -> Self { + RepType::Subset(value, Subsets::default(), Option::None) + } +} + impl From, Obj)>> for RepType<(Option, Obj)> { fn from(value: Vec<(Option, Obj)>) -> Self { // FIXME: How to handle names? From c6c077ca9fe7ccc9ce21c151d5fa9a451f75292f Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 25 Sep 2024 16:00:17 +0530 Subject: [PATCH 11/49] rep now covers list I think --- src/object/list.rs | 64 --------------------------- src/object/vector/rep.rs | 85 ++++++++++++++++-------------------- src/object/vector/reptype.rs | 62 ++++++++++++++++++++++++-- src/object/vector/subsets.rs | 5 +-- 4 files changed, 99 insertions(+), 117 deletions(-) diff --git a/src/object/list.rs b/src/object/list.rs index 5c1d634f..5a1cf9d1 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -9,70 +9,6 @@ use super::*; type ListNameMap = HashMap>; -struct List2(Rep); - -impl From> for List2 { - fn from(x: Rep) -> Self { - List2(x) - } -} - -impl List2 { - pub fn reindex(&mut self) { - self.0.reindex() - } - - pub fn assign(&mut self, other: Obj) -> EvalResult { - todo!() - } - - pub fn try_get(&self, index: Obj) -> EvalResult { - let err = Error::Other("Cannot use object for indexing".to_string()); - todo!() - // match index.as_vector()? { - // Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), - // _ => Err(err.into()), - // } - } - - pub fn try_get_inner(&self, index: Obj) -> EvalResult { - // #[allow(clippy::map_clone)] - // self.try_get_inner_mut(index).map(|v| v.clone()) - todo!() - } - - pub fn subset(&self, subset: Subset) -> Self { - self.0.subset(subset).into() - } - - pub fn len(&self) -> usize { - self.0.len() - } - - #[must_use] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn materialize(self) -> Self { - List2::from(self.0.materialize()) - } - - pub fn assign(&mut self, other: Obj) -> EvalResult { - // TODO: Rep currently does not handle names. - todo!() - } - - /// Get the names of the vector. - pub fn names(&self) -> Option>> { - self.0.names() - } - - pub fn set_names_(&self, names: CowObj>) { - self.0.set_names_(names) - } -} - #[derive(Debug, Clone, PartialEq, Default)] pub struct List { pub names: CowObj, diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 41a2ce53..09e5196e 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -8,8 +8,7 @@ use super::reptype::RepTypeIter; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::object::reptype::Naming; -use crate::object::vector::*; +use crate::error::Error; use crate::object::{CowObj, Obj, ViewMut}; /// Vector Representation @@ -38,16 +37,41 @@ impl ViewMut for Rep { } impl Rep { - pub fn get_inner_mut(&self, index: usize) -> Option { - self.0.borrow().get_inner_mut(index) - } - - pub fn try_get_inner_mut(&self, subset: Subset) -> Option { - + /// Get the inner value mutably. + /// This is used for assignments like `list(1)[[1]] = 10`. + pub fn try_get_inner_mut(&self, subset: Subset) -> Result { + match self.borrow().clone() { + RepType::Subset(values, mut subsets, maybe_naming) => { + subsets.push(subset); + if let Some(naming) = maybe_naming { + let mut iter = subsets.bind_names(naming.map).into_iter(); + + // Here, the subset must produce exactly one index, i.e. we call next() twice and the second + // yielded element must be None + if let Some((i, _)) = iter.next() { + if let None = iter.next() { + values.with_inner_mut(|v| { + v.get_mut(i) + .map_or(Err(Error::Other("todo".to_string())), |x| { + Ok(x.view_mut()) + }) + }) + } else { + Err(Error::Other("todo".to_string())) + } + } else { + Err(Error::Other("todo".to_string())) + } + } else { + // TODO + Err(Error::Other("todo".to_string())) + } + } + } } - pub fn try_get_inner(&self, subset: Subset) -> T { - + pub fn try_get_inner(&self, subset: Subset) -> Result { + self.try_get_inner_mut(subset).map(|v| v.clone()) } } @@ -59,8 +83,8 @@ where self.0.borrow() } - pub fn try_get(&self, subset: Subset) -> T { - + pub fn borrow_mut(&mut self) -> RefMut> { + self.0.borrow_mut() } pub fn iter_names(&self) -> Option>>> { @@ -71,10 +95,6 @@ where } } - pub fn borrow_mut(&mut self) -> RefMut> { - self.0.borrow_mut() - } - fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily let new_repr = { self.borrow().materialize() }; @@ -111,37 +131,7 @@ where } pub fn dedup_last(self) -> Self { - todo!() - // Note: We need to ensure here that we duplicate the names and the values. - // Previously this was stored in one vector with tuples but now this is split up - if let RepType::Subset(values) - - self.names.with_inner_mut(|names| { - let mut dups: Vec = names - .iter() - .flat_map(|(_, indices)| { - indices - .split_last() - .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) - }) - .collect(); - - dups.sort(); - - self.values.with_inner_mut(|vs| { - for i in dups.into_iter().rev() { - vs.remove(i); - } - }); - }); - - self.names.with_inner_mut(|names| { - for (_, indices) in names.iter_mut() { - indices.drain(0..indices.len()); - } - }); - - self + self.0.into_inner().dedup_last().into() } /// Try to get mutable access to the internal vector through the passed closure. @@ -211,6 +201,7 @@ where } pub fn assign(&mut self, value: Self) -> Self { + // TODO: Handle names here self.0.borrow_mut().assign(value.0.into_inner()).into() } /// Test the mode of the internal vector type diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 59e8e523..dfbe78e0 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -32,6 +32,15 @@ impl Naming { }); }; } + + /// Get mutable access to the internal vector through the passed closure. + pub fn with_inner_mut(&self, f: F) -> R + where + F: FnOnce(&mut HashMap>, &mut Vec>) -> R, + { + self.map + .with_inner_mut(|map| self.names.with_inner_mut(|names| f(map, names))) + } } impl From>> for Naming { @@ -80,7 +89,7 @@ impl Default for RepType { impl RepType { /// Retrieve the internal data as a mutable view. - pub fn get_inner_mut(&self, index: usize) -> Option { + pub fn try_get_inner_mut(&self, index: usize) -> Option { match self { RepType::Subset(v, subsets, _) => { let vb = v.borrow(); @@ -177,6 +186,53 @@ impl RepType { } } + pub fn iter_indices(&self) -> Box)>> { + match self.clone() { + RepType::Subset(_, subsets, Some(naming)) => { + Box::new(subsets.bind_names(naming.map).into_iter()) + } + RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), + } + } + + pub fn with_iter_mut(&self, f: F) + where + F: FnOnce(Box>), + { + } + + pub fn dedup_last(self) -> Self { + match self { + RepType::Subset(values, subsets, Some(naming)) => { + naming.with_inner_mut(|map, names| { + let mut dups: Vec = map + .iter() + .flat_map(|(_, indices)| { + indices + .split_last() + .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) + }) + .collect(); + + dups.sort(); + + values.with_inner_mut(|vs| { + for i in dups.into_iter().rev() { + vs.remove(i); + names.remove(i); + } + }); + + for (_, indices) in map.iter_mut() { + indices.drain(0..indices.len()); + } + }); + RepType::Subset(values, subsets, Some(naming)) + } + RepType::Subset(.., None) => return self, + } + } + pub fn set_names(&self, names: CowObj>) -> Self { match self { RepType::Subset(v, s, _) => { @@ -259,6 +315,8 @@ impl RepType { where T: Clone + Default, { + let l_indices = self.iter_indices(); + let r_indices = value.iter_indices(); match (self, value) { (RepType::Subset(lv, ls, ln), RepType::Subset(rv, rs, _)) => { lv.with_inner_mut(|lvb| { @@ -266,8 +324,6 @@ impl RepType { let rvb = rvc.borrow(); let lv_len = lvb.len(); - let l_indices = ls.clone().into_iter().take_while(|(i, _)| i < &lv_len); - let r_indices = rs.clone().into_iter().take_while(|(i, _)| i < &lv_len); for ((_, li), (_, ri)) in l_indices.zip(r_indices) { match (li, ri) { diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index c6d2b4cc..d6f0b6a8 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -41,12 +41,11 @@ impl Subsets { self.len() == 0 } - pub fn push(self, subset: T) + pub fn push(&mut self, subset: T) where T: Into, { - let Subsets(mut v) = self; - v.push(subset.into()); + self.0.push(subset.into()); } pub fn bind_names(self, names: CowObj>>) -> NamedSubsets { From 692fbcdb1626fa2b02bcdd50a43cd6d283c70741 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Thu, 26 Sep 2024 16:20:50 +0530 Subject: [PATCH 12/49] ... --- src/callable/core.rs | 91 +++--- src/object/cow.rs | 13 + src/object/environment.rs | 13 +- src/object/list.rs | 534 +++++++++++++++++------------------ src/object/vector/rep.rs | 64 ++++- src/object/vector/reptype.rs | 220 +++++++++++++-- 6 files changed, 596 insertions(+), 339 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index e812723e..6b2262d4 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -5,6 +5,7 @@ use crate::callable::dyncompare::*; use crate::cli::Experiment; use crate::context::Context; use crate::error::Error; +use crate::object::types::Character; use crate::object::List; use crate::object::{Expr, ExprList, Obj}; use crate::{internal_err, lang::*}; @@ -38,17 +39,26 @@ pub trait Callable { fn match_args(&self, args: List, stack: &mut CallStack) -> Result<(List, List), Signal> { let mut formals = self.formals(); - let ellipsis: List = vec![].into(); - let matched_args: List = vec![].into(); + let ellipsis: List = List::new(); + let matched_args: List = List::new(); // assign named args to corresponding formals + + // What we do here: + // 1. We iterate over the args values, check whether the value is named. + // 2. If this is also a formal, we add it to the matched list. + // 3. Otherwise we keep iterating. + // We need the special 'inner context because we are acessing args.values mutable and immutably. + + // How else can we implement this? + let mut i: usize = 0; - 'outer: while i < args.values.len() { + 'outer: while i < args.len() { 'inner: { // check argname with immutable borrow, but drop scope. If // found, drop borrow so we can mutably assign it - if let (Some(argname), _) = &args.values.borrow()[i] { - if let Some((Some(_), _)) = formals.remove_named(argname) { + if let (Character::Some(argname), _) = args.get_inner_named(i).unwrap() { + if let Some((Some(_), _)) = formals.remove_named(&argname) { break 'inner; } } @@ -57,9 +67,12 @@ pub trait Callable { continue 'outer; } - matched_args - .values - .with_inner_mut(|v| v.push(args.values.with_inner_mut(|x| x.remove(i)))) + // 1. Remove the name and value from args + // 2. Push them to matched args + + let (name, obj) = args.remove(i); + + matched_args.push_named(name, obj) } // TODO(bug): need to evaluate trailing unassigned params that have @@ -69,50 +82,43 @@ pub trait Callable { let remainder = formals.pop_trailing(); // backfill unnamed args, populating ellipsis with overflow - let argsiter = args.values.into_iter(); - for (key, value) in argsiter { + args.with_pairs(|key, value| { match key { // named args go directly to ellipsis, they did not match a formal - Some(arg) => { - ellipsis - .values - .with_inner_mut(|v| v.push((Some(arg), value))); - } + Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value), // unnamed args populate next formal, or ellipsis if formals exhausted - None => { + Character::NA => { let next_unassigned_formal = formals.remove(0); if let Some((Some(param), _)) = next_unassigned_formal { - matched_args - .values - .with_inner_mut(|vals| vals.push((Some(param), value))); + matched_args.push_named(Character::Some(param), value); } else { - ellipsis - .values - .with_inner_mut(|vals| vals.push((None, value))); + ellipsis.push_named(Character::NA, value); } } } - } + }); // add back in parameter defaults that weren't filled with args for (param, default) in formals.into_iter() { - matched_args.values.with_inner_mut(|v| { - v.push(( - param, - Obj::Promise(None, default, stack.last_frame().env().clone()), - )); - }) + let param = if let Some(param) = param { + Character::Some(param) + } else { + Character::NA + }; + matched_args.push_named( + param, + Obj::Promise(None, default, stack.last_frame().env().clone()), + ) } if let Some(Expr::Ellipsis(Some(name))) = remainder.get(0) { - matched_args - .values - .with_inner_mut(|v| v.push((Some(name), Obj::List(ellipsis.clone())))) + matched_args.push_named(Character::Some(name), Obj::List(ellipsis.clone())); } else if !remainder.is_empty() { - matched_args - .values - .with_inner_mut(|v| v.push((Some("...".to_string()), Obj::List(ellipsis.clone())))) + matched_args.push_named( + Character::Some("...".to_string()), + Obj::List(ellipsis.clone()), + ); } Ok((matched_args, ellipsis)) @@ -293,13 +299,22 @@ pub fn force_promises( ) -> Result, Obj)>, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. - vals.values - .into_iter() - .map(|(k, v)| match (k, v.force(stack)) { + let x = vals.with_iter_pairs(|iter| { + iter.map(|(k, v)| match (k, v.force(stack)) { (k, Ok(v)) => Ok((k, v)), (_, Err(e)) => Err(e), }) .collect() + }); + // vals.with_iter_pairs(|k, v| { + // (k, Ok(v)) => Ok((k, v)), + // (_, Err(e)) => Err(e), + // }) + // vals.values + // .into_iter() + // .map(|(k, v)| match (k, v.force(stack)) { + // }) + // .collect() } impl Format for String { diff --git a/src/object/cow.rs b/src/object/cow.rs index 0bfdcfdc..3a2b5b2a 100644 --- a/src/object/cow.rs +++ b/src/object/cow.rs @@ -72,6 +72,19 @@ impl CowObj { f(vals) } + /// Get immutable access to the internal vector. + /// In case more than one reference to the internal data exists, + /// the vector is cloned. + pub fn with_inner(&self, f: F) -> R + where + F: FnOnce(&T) -> R, + { + let CowObj(x) = self; + let x1 = &mut *x.borrow_mut(); + let vals: &T = Rc::make_mut(x1); + f(vals) + } + /// Borrow the internal data immutably. pub fn borrow(&self) -> Ref<'_, Rc> { self.0.borrow() diff --git a/src/object/environment.rs b/src/object/environment.rs index 232d79ba..e2d2ee05 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -55,11 +55,18 @@ impl Environment { } pub fn append(&self, l: List) { - for (key, value) in l.values.iter() { - if let Some(name) = key { - self.values.borrow_mut().insert(name.clone(), value.clone()); + let iter = l.iter_pairs(); + + if let Some(iter) { + for (key, value) in l.iter_paier { + if let Some(name) = key { + self.values.borrow_mut().insert(name.clone(), value.clone()); + } } + } + + } pub fn get(&self, name: String) -> EvalResult { diff --git a/src/object/list.rs b/src/object/list.rs index 5a1cf9d1..a8d26fa1 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -7,278 +7,268 @@ use crate::object::vector::types::Character; use super::*; -type ListNameMap = HashMap>; - -#[derive(Debug, Clone, PartialEq, Default)] -pub struct List { - pub names: CowObj, - pub values: CowObj, Obj)>>, - pub subsets: Subsets, -} - -impl From, Obj)>> for List { - fn from(value: Vec<(Option, Obj)>) -> Self { - let mut result = List { - values: CowObj::from(value), - ..Default::default() - }; - - result.reindex(); - result - } -} - -impl List { - pub fn reindex(&mut self) { - self.names.with_inner_mut(|names| { - names.drain(); - - for (i, (k, _)) in self.values.borrow().iter().enumerate() { - if let Some(name) = k { - let indices = names.entry(name.clone()).or_default(); - if !indices.contains(&i) { - indices.push(i) - } - } - } - }) - } - - pub fn subset(&self, by: Subset) -> List { - let Subsets(mut inner) = self.subsets.clone(); - inner.push(by); - List { - names: self.names.clone(), - values: self.values.view_mut(), - subsets: Subsets(inner), - } - } - - pub fn assign(&mut self, value: Obj) -> EvalResult { - match value { - // remove elements from list - Obj::Null => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - - self.values.with_inner_mut(|values| { - for (i, _) in indices { - values.remove(i); - } - }); - - self.reindex(); - - // TODO(feat): need to return list with NULL elements when - // index is NA - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) - } - - // any single length R value - any if any.len() == Some(1) => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - - self.values.with_inner_mut(|v| { - // first check to see if we need to extend - if let Some(max) = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .map(|(i, _)| i) - .max() - { - v.reserve(max.saturating_sub(n)) - } - - // then assign to indices - for (_, i) in indices { - if let Some(i) = i { - v[i].1 = any.clone() - } - } - }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) - } - // vectorized assignment - // TODO(feature): warn when index recycling does not cycle evenly - any if any.len() == Some(self.len()) => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - - self.values.with_inner_mut(|v| { - // first check to see if we need to extend - if let Some(max) = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .map(|(i, _)| i) - .max() - { - v.reserve(max.saturating_sub(n)) - } - - // then assign to indices - for (any_i, (_, i)) in indices.enumerate() { - if let (Some(value), Some(i)) = (any.get(any_i), i) { - v[i].1 = value; - } - } - }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) - } - other => { - let n = self.values.len(); - let indices = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .take(n); - - self.values.with_inner_mut(|v| { - // first check to see if we need to extend - if let Some(max) = self - .subsets - .clone() - .bind_names(self.names.clone()) - .into_iter() - .map(|(i, _)| i) - .max() - { - v.reserve(max.saturating_sub(n)) - } - - // then assign to indices - for (_, i) in indices { - if let Some(i) = i { - v[i].1 = other.clone() - } - } - }); - - Ok(Obj::List(List { - names: self.names.clone(), - values: self.values.clone(), - subsets: self.subsets.clone(), - })) - } - } - } - - pub fn try_get(&self, index: Obj) -> EvalResult { - let err = Error::Other("Cannot use object for indexing".to_string()); - match index.as_vector()? { - Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), - _ => Err(err.into()), - } - } - - pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { - let err_invalid = Error::Other("Cannot use object for indexing".to_string()); - let err_index_invalid = Error::Other("Index out of bounds".to_string()); - - match index.as_vector()? { - Obj::Vector(v) if v.len() == 1 => { - let Subsets(mut subsets) = self.subsets.clone(); - subsets.push(v.try_into()?); - - if let Some((i, _)) = Subsets(subsets) - .bind_names(self.names.clone()) - .into_iter() - .next() - { - self.values.with_inner_mut(|v| { - v.get_mut(i) - .map_or(Err(err_index_invalid.into()), |(_, i)| Ok(i.view_mut())) - }) - } else { - Ok(Obj::Null) - } - } - _ => Err(err_invalid.into()), - } - } - - pub fn try_get_inner(&self, index: Obj) -> EvalResult { - #[allow(clippy::map_clone)] - self.try_get_inner_mut(index).map(|v| v.clone()) - } - - pub fn dedup_last(self) -> Self { - self.names.with_inner_mut(|names| { - let mut dups: Vec = names - .iter() - .flat_map(|(_, indices)| { - indices - .split_last() - .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) - }) - .collect(); - - dups.sort(); - - self.values.with_inner_mut(|vs| { - for i in dups.into_iter().rev() { - vs.remove(i); - } - }); - }); - - self.names.with_inner_mut(|names| { - for (_, indices) in names.iter_mut() { - indices.drain(0..indices.len()); - } - }); - - self - } - - pub fn len(&self) -> usize { - let Subsets(inner) = &self.subsets; - match inner.as_slice() { - [] => self.values.borrow().len(), - [.., last] => std::cmp::min(self.values.borrow().len(), last.len()), - } - } - - #[must_use] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} +pub type List = Rep; + +// type ListNameMap = HashMap>; + +// #[derive(Debug, Clone, PartialEq, Default)] +// pub struct List { +// pub names: CowObj, +// pub values: CowObj, Obj)>>, +// pub subsets: Subsets, +// } + +// impl List { +// pub fn reindex(&mut self) { +// self.names.with_inner_mut(|names| { +// names.drain(); + +// for (i, (k, _)) in self.values.borrow().iter().enumerate() { +// if let Some(name) = k { +// let indices = names.entry(name.clone()).or_default(); +// if !indices.contains(&i) { +// indices.push(i) +// } +// } +// } +// }) +// } + +// pub fn subset(&self, by: Subset) -> List { +// let Subsets(mut inner) = self.subsets.clone(); +// inner.push(by); +// List { +// names: self.names.clone(), +// values: self.values.view_mut(), +// subsets: Subsets(inner), +// } +// } + +// pub fn assign(&mut self, value: Obj) -> EvalResult { +// match value { +// // remove elements from list +// Obj::Null => { +// let n = self.values.len(); +// let indices = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .take(n); + +// self.values.with_inner_mut(|values| { +// for (i, _) in indices { +// values.remove(i); +// } +// }); + +// self.reindex(); + +// // TODO(feat): need to return list with NULL elements when +// // index is NA + +// Ok(Obj::List(List { +// names: self.names.clone(), +// values: self.values.clone(), +// subsets: self.subsets.clone(), +// })) +// } + +// // any single length R value +// any if any.len() == Some(1) => { +// let n = self.values.len(); +// let indices = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .take(n); + +// self.values.with_inner_mut(|v| { +// // first check to see if we need to extend +// if let Some(max) = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .map(|(i, _)| i) +// .max() +// { +// v.reserve(max.saturating_sub(n)) +// } + +// // then assign to indices +// for (_, i) in indices { +// if let Some(i) = i { +// v[i].1 = any.clone() +// } +// } +// }); + +// Ok(Obj::List(List { +// names: self.names.clone(), +// values: self.values.clone(), +// subsets: self.subsets.clone(), +// })) +// } +// // vectorized assignment +// // TODO(feature): warn when index recycling does not cycle evenly +// any if any.len() == Some(self.len()) => { +// let n = self.values.len(); +// let indices = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .take(n); + +// self.values.with_inner_mut(|v| { +// // first check to see if we need to extend +// if let Some(max) = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .map(|(i, _)| i) +// .max() +// { +// v.reserve(max.saturating_sub(n)) +// } + +// // then assign to indices +// for (any_i, (_, i)) in indices.enumerate() { +// if let (Some(value), Some(i)) = (any.get(any_i), i) { +// v[i].1 = value; +// } +// } +// }); + +// Ok(Obj::List(List { +// names: self.names.clone(), +// values: self.values.clone(), +// subsets: self.subsets.clone(), +// })) +// } +// other => { +// let n = self.values.len(); +// let indices = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .take(n); + +// self.values.with_inner_mut(|v| { +// // first check to see if we need to extend +// if let Some(max) = self +// .subsets +// .clone() +// .bind_names(self.names.clone()) +// .into_iter() +// .map(|(i, _)| i) +// .max() +// { +// v.reserve(max.saturating_sub(n)) +// } + +// // then assign to indices +// for (_, i) in indices { +// if let Some(i) = i { +// v[i].1 = other.clone() +// } +// } +// }); + +// Ok(Obj::List(List { +// names: self.names.clone(), +// values: self.values.clone(), +// subsets: self.subsets.clone(), +// })) +// } +// } +// } + +// pub fn try_get(&self, index: Obj) -> EvalResult { +// let err = Error::Other("Cannot use object for indexing".to_string()); +// match index.as_vector()? { +// Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), +// _ => Err(err.into()), +// } +// } + +// pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { +// let err_invalid = Error::Other("Cannot use object for indexing".to_string()); +// let err_index_invalid = Error::Other("Index out of bounds".to_string()); + +// match index.as_vector()? { +// Obj::Vector(v) if v.len() == 1 => { +// let Subsets(mut subsets) = self.subsets.clone(); +// subsets.push(v.try_into()?); + +// if let Some((i, _)) = Subsets(subsets) +// .bind_names(self.names.clone()) +// .into_iter() +// .next() +// { +// self.values.with_inner_mut(|v| { +// v.get_mut(i) +// .map_or(Err(err_index_invalid.into()), |(_, i)| Ok(i.view_mut())) +// }) +// } else { +// Ok(Obj::Null) +// } +// } +// _ => Err(err_invalid.into()), +// } +// } + +// pub fn try_get_inner(&self, index: Obj) -> EvalResult { +// #[allow(clippy::map_clone)] +// self.try_get_inner_mut(index).map(|v| v.clone()) +// } + +// pub fn dedup_last(self) -> Self { +// self.names.with_inner_mut(|names| { +// let mut dups: Vec = names +// .iter() +// .flat_map(|(_, indices)| { +// indices +// .split_last() +// .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) +// }) +// .collect(); + +// dups.sort(); + +// self.values.with_inner_mut(|vs| { +// for i in dups.into_iter().rev() { +// vs.remove(i); +// } +// }); +// }); + +// self.names.with_inner_mut(|names| { +// for (_, indices) in names.iter_mut() { +// indices.drain(0..indices.len()); +// } +// }); + +// self +// } + +// pub fn len(&self) -> usize { +// let Subsets(inner) = &self.subsets; +// match inner.as_slice() { +// [] => self.values.borrow().len(), +// [.., last] => std::cmp::min(self.values.borrow().len(), last.len()), +// } +// } + +// #[must_use] +// pub fn is_empty(&self) -> bool { +// self.len() == 0 +// } +// } #[cfg(test)] mod tests { diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 09e5196e..4037cb28 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -87,13 +87,21 @@ where self.0.borrow_mut() } - pub fn iter_names(&self) -> Option>>> { - if let Some(names) = self.names() { - Some(Box::new(names.iter())) - } else { - None - } - } + /// Iterate over the (owned) values of the vector. + // pub fn iter_values(&self) -> Box + '_> { + // let x = self.0.borrow().clone(); + // x.into_iter() + // } + + // /// Iterate over the names of the vector (if they exist). + // pub fn iter_names(&self) -> Option>> { + // self.0.borrow().iter_names() + // } + + // /// Iterate over the names and values of the vector (if the names exist). + // pub fn iter_pairs(&self) -> Option>> { + // self.0.borrow().iter_named() + // } fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily @@ -103,6 +111,10 @@ where self } + pub fn remove(&self, index: usize) -> (Character, T) { + self.borrow().remove(index) + } + /// Reindex the mapping from names to indices. pub fn reindex(&mut self) { self.borrow_mut().reindex() @@ -134,7 +146,7 @@ where self.0.into_inner().dedup_last().into() } - /// Try to get mutable access to the internal vector through the passed closure. + /// Get mutable access to the internal vector through the passed closure. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut Vec) -> R, @@ -142,6 +154,30 @@ where self.0.borrow().with_inner_mut(f) } + /// Iterates over owned (name, value) tuples. + pub fn with_pairs(&self, f: F) + where + F: FnMut(Character, T) -> R, + { + self.borrow().with_pairs(f) + } + + /// Iterates over owned (name, value) tuples. + pub fn with_iter_pairs(&self, f: F) + where + F: FnMut(Box>) -> R, + { + todo!() + } + + /// Get immutable access to the internal vector through the passed closure. + pub fn with_inner(&self, f: F) -> R + where + F: FnOnce(&Vec) -> R, + { + self.0.borrow().with_inner(f) + } + pub fn materialize(&self) -> Self { self.borrow().materialize().into() } @@ -200,6 +236,18 @@ where self.borrow().get_inner(index) } + pub fn get_inner_named(&self, index: usize) -> Option<(Character, T)> { + self.borrow().get_inner_named(index) + } + + pub fn push(&self, value: T) { + self.borrow().push(value) + } + + pub fn push_named(&self, name: OptionNA, value: T) { + self.borrow().push_named(name, value) + } + pub fn assign(&mut self, value: Self) -> Self { // TODO: Handle names here self.0.borrow_mut().assign(value.0.into_inner()).into() diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index dfbe78e0..c561fe34 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -6,6 +6,7 @@ use super::subset::Subset; use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; +use crate::callable::dyncompare::AsDynCompare; use crate::object::{CowObj, Obj, ViewMut}; use hashbrown::HashMap; @@ -20,6 +21,18 @@ impl Naming { pub fn new() -> Self { Naming::default() } + + pub fn remove(&self, index: usize) -> Character { + // FIXME: Already assumes names are unique + let maybe_name = self.names.with_inner_mut(|names| names.remove(index)); + if let OptionNA::Some(name) = maybe_name { + self.map.with_inner_mut(|map| map.remove(&name)); + OptionNA::Some(name) + } else { + OptionNA::NA + } + } + pub fn push_name(&self, name: OptionNA) { self.names.with_inner_mut(|v| v.push(name.clone())); if let OptionNA::Some(name) = name { @@ -164,7 +177,164 @@ impl RepType { /// ``` /// pub fn new() -> Self { - RepType::Subset(Vec::new().into(), Subsets(Vec::new()), Option::None) + RepType::Subset( + Vec::new().into(), + Subsets(Vec::new()), + Some(Naming::default()), + ) + } + + /// Preallocates a RepType with the given capacity. + pub fn with_capacity(n: usize) { + todo!() + } + + pub fn ensure_named(&self) { + todo!() + } + + pub fn with_iter_pairs(&self, f: F) + where + F: FnMut(Box>) -> R, + { + todo!() + } + + /// Iterates over owned (name, value) tuples. + pub fn with_pairs(&self, f: F) + where + F: FnMut(Character, T) -> R, + { + todo!() + } + + /// Iterates over owned (name, value) tuples. + pub fn with_iter_pairs_mut(&self, f: F) + where + F: Fn(&mut Character, &mut T) -> R, + { + todo!() + } + + /// Iterates over name, value pairs + pub fn with_iter_values(&self, f: F) + where + F: Fn(&T) -> R, + { + todo!() + } + + /// Iterates over name, value pairs + pub fn with_iter_values_mut(&self, f: F) + where + F: Fn(&T) -> R, + { + todo!() + } + + /// Iterates over name, value pairs + pub fn with_iter_names(&self, f: F) + where + F: Fn(&Character) -> R, + { + todo!() + } + + /// Iterates over name, value pairs + pub fn with_iter_names(&self, f: F) + where + F: Fn(&Character) -> R, + { + todo!() + } + + pub fn with_iter_ref(&self, f: F) + where + F: FnOnce(&T) -> R, + { + todo!() + } + + pub fn with_iter_ref_mut(&self, f: F) + where + F: FnOnce(&T) -> R, + { + todo!() + } + + pub fn push_value(&self, value: T) { + self.push_named(Character::NA, value); + } + + pub fn remove(&self, index: usize) -> (Character, T) { + match self { + RepType::Subset(values, Subsets(subsets), maybe_naming) => { + if let [] = subsets.as_slice() { + let value = values.with_inner_mut(|values| values.remove(index)); + + let name = if let Some(naming) = maybe_naming { + naming.remove(index) + } else { + OptionNA::NA + }; + return (name, value); + } else { + unimplemented!() + } + } + } + } + + pub fn push_named(&self, name: OptionNA, value: T) { + match self { + RepType::Subset(values, Subsets(subsets), maybe_naming) => match subsets.as_slice() { + [] => { + values.with_inner_mut(|values| values.push(value)); + if let Some(naming) = maybe_naming { + naming.push_name(name) + } + } + _ => unimplemented!(), + }, + } + } + + pub fn iter_values<'a>(&'a self) -> Box + 'a> { + let iter = self.iter_subset_indices(); + match self.clone() { + RepType::Subset(values, ..) => Box::new(iter.map(move |(_, i)| { + let i = i.unwrap(); + let vb = values.borrow(); + (&vb[i]).clone() + })), + } + } + + pub fn iter_names(&self) -> Option>> { + let iter = self.iter_subset_indices(); + match self.clone() { + RepType::Subset(.., None) => None, + RepType::Subset(.., Some(naming)) => Some(Box::new(iter.map(move |(_, i)| { + let i = i.unwrap(); + let vb = naming.names.borrow(); + (&vb[i]).clone() + }))), + } + } + + pub fn iter_named<'a>(&'a self) -> Option + 'a>> { + let iter_names = self.iter_names()?; + Some(Box::new(iter_names.zip(self.iter_values()))) + } + + // TODO(refactor): This is internal implementation detail and should not be exposed via the API. + pub fn iter_subset_indices(&self) -> Box)>> { + match self.clone() { + RepType::Subset(_, subsets, Some(naming)) => { + Box::new(subsets.bind_names(naming.map).into_iter()) + } + RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), + } } /// Reindex the mapping from names to indices. @@ -186,22 +356,8 @@ impl RepType { } } - pub fn iter_indices(&self) -> Box)>> { - match self.clone() { - RepType::Subset(_, subsets, Some(naming)) => { - Box::new(subsets.bind_names(naming.map).into_iter()) - } - RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), - } - } - - pub fn with_iter_mut(&self, f: F) - where - F: FnOnce(Box>), - { - } - pub fn dedup_last(self) -> Self { + // TODO(docu): What exactly does this? I think there might still be a bug here because we drain ALL indices (?) match self { RepType::Subset(values, subsets, Some(naming)) => { naming.with_inner_mut(|map, names| { @@ -258,6 +414,16 @@ impl RepType { } } + /// Get mutable access to the internal vector through the passed closure. + pub fn with_inner(&self, f: F) -> R + where + F: FnOnce(&Vec) -> R, + { + match self { + RepType::Subset(v, ..) => v.with_inner(f), + } + } + /// Subsetting a Vector /// /// Introduce a new subset into the aggregate list of subset indices. @@ -315,8 +481,11 @@ impl RepType { where T: Clone + Default, { - let l_indices = self.iter_indices(); - let r_indices = value.iter_indices(); + // TODO(feature): here we should also throw an error if the recycling rules are violated. + // TODO(refactor): I don't think we should ever iterate over the indices. + // Instead the API of RepType should conveniently, i.e. offer Iterators that yield mutable / immutable references to the Ts. + let l_indices = self.iter_subset_indices(); + let r_indices = value.iter_subset_indices(); match (self, value) { (RepType::Subset(lv, ls, ln), RepType::Subset(rv, rs, _)) => { lv.with_inner_mut(|lvb| { @@ -497,6 +666,21 @@ impl RepType { } } } + pub fn get_inner_named(&self, index: usize) -> Option<(OptionNA, T)> { + match &self { + RepType::Subset(.., maybe_naming) => { + let x = self.get_inner(index)?; + if let Some(naming) = maybe_naming { + Some(( + OptionNA::Some(naming.names.borrow().get(index).unwrap().to_string()), + x, + )) + } else { + Some((OptionNA::NA, x)) + } + } + } + } } impl TryInto for RepType> From 9ff1ad602d4057703b7d6de8cce17ba9856565ba Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 27 Sep 2024 09:53:51 +0530 Subject: [PATCH 13/49] ... --- src/callable/core.rs | 7 +- src/callable/primitive/c.rs | 143 +++++++++++++--------------- src/callable/primitive/callstack.rs | 2 +- src/callable/primitive/names.rs | 8 +- src/callable/primitive/paste.rs | 3 +- src/context/core.rs | 43 +++++---- src/lang.rs | 11 +-- src/object/vector/core.rs | 26 ++++- src/object/vector/rep.rs | 26 ++++- src/object/vector/reptype.rs | 67 +++++++++++-- 10 files changed, 209 insertions(+), 127 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 6b2262d4..2616d8e7 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -293,10 +293,7 @@ impl TryFrom<&str> for Box { } } -pub fn force_promises( - vals: List, - stack: &mut CallStack, -) -> Result, Obj)>, Signal> { +pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. let x = vals.with_iter_pairs(|iter| { @@ -306,6 +303,8 @@ pub fn force_promises( }) .collect() }); + x + // vals.with_iter_pairs(|k, v| { // (k, Ok(v)) => Ok((k, v)), // (_, Err(e)) => Err(e), diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index b89cf26d..c3e35e3d 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -51,27 +51,28 @@ impl Callable for PrimitiveC { }; // lets first see what we're aiming to build. - let ty: u8 = vals - .values - .iter() - .map(|(_, v)| match v { + let ty: u8 = vals.with_iter_pairs(|iter| { + iter.map(|(_, v)| match v { Obj::Null => 0, Obj::Vector(_) => 1, Obj::List(_) => 2, _ => 0, }) - .fold(0, std::cmp::max); + .fold(0, std::cmp::max) + }); // if the output will have names - let named = vals.values.borrow().iter().any(|(n, o)| { - if n.is_some() { - return true; - } - match o { - Obj::Vector(v) => v.names().is_none(), - Obj::List(l) => l.names.borrow().len() > 0, - _ => todo!(), - } + let named = vals.with_iter_pairs(|mut iter| { + iter.any(|(n, o)| { + if matches!(n, OptionNA::Some(_)) { + return true; + } + match o { + Obj::Vector(v) => v.is_named(), + Obj::List(l) => l.is_named(), + _ => todo!(), + } + }) }); // most complex type was NULL @@ -86,42 +87,49 @@ impl Callable for PrimitiveC { } let names: Option> = if named { - let nms = vals.values.iter().flat_map(|(name, obj)| { - let maybe_prefix = name.as_ref().and_then(|n| Option::Some(n.clone())); + let nms = vals.with_iter_pairs(|iter| { + iter.flat_map(|(name, obj)| { + let maybe_prefix = name + .as_option() + .as_ref() + .and_then(|n| Option::Some(n.clone())); - if let Obj::Vector(v) = obj { - let maybe_names_iter = v.iter_names(); + if let Obj::Vector(v) = obj { + let maybe_names_iter = v.iter_names(); - let x: Vec = match (maybe_prefix, maybe_names_iter) { - (None, None) => std::iter::repeat(Character::NA).take(v.len()).collect(), - (Some(prefix), None) => std::iter::repeat(Character::Some(prefix.clone())) - .take(v.len()) - .collect(), - (None, Some(names_iter)) => names_iter.collect(), - (Some(prefix), Some(names_iter)) => names_iter - .map(|maybe_name| { - if let OptionNA::Some(name) = maybe_name { - Character::Some(format!("{}.{}", prefix, name)) - } else { - Character::Some(prefix.clone()) - } - }) - .collect(), - }; - x - } else { - unimplemented!() - } + let x: Vec = match (maybe_prefix, maybe_names_iter) { + (None, None) => { + std::iter::repeat(Character::NA).take(v.len()).collect() + } + (Some(prefix), None) => { + std::iter::repeat(Character::Some(prefix.clone())) + .take(v.len()) + .collect() + } + (None, Some(names_iter)) => names_iter.collect(), + (Some(prefix), Some(names_iter)) => names_iter + .map(|maybe_name| { + if let OptionNA::Some(name) = maybe_name { + Character::Some(format!("{}.{}", prefix, name)) + } else { + Character::Some(prefix.clone()) + } + }) + .collect(), + }; + x + } else { + unimplemented!() + } + }) }); Some(nms.collect()) } else { None }; - let ret = vals - .values - .iter() - .map(|(_, r)| match r { + let ret = vals.with_iter_pairs(|iter| { + iter.map(|(_, r)| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Integer(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Double(_)) => Vector::from(Vec::::new()), @@ -136,60 +144,45 @@ impl Callable for PrimitiveC { (v @ Vector::Integer(_), _) => v, (_, v @ Vector::Integer(_)) => v, (v @ Vector::Logical(_), _) => v, - }); + }) + }); // consume values and merge into a new collection let v = match ret { Vector::Character(_) => Vector::from( Vec::>::new() .into_iter() - .chain( - vals.values - .into_iter() - .flat_map(|(_, i)| match i.as_character() { - Ok(Obj::Vector(Vector::Character(v))) => v.into_iter(), - _ => unreachable!(), - }), - ) + .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_character() { + Ok(Obj::Vector(Vector::Character(v))) => v.into_iter(), + _ => unreachable!(), + })) .collect::>(), ), Vector::Double(_) => Vector::from( Vec::>::new() .into_iter() - .chain( - vals.values - .into_iter() - .flat_map(|(_, i)| match i.as_double() { - Ok(Obj::Vector(Vector::Double(v))) => v.into_iter(), - _ => unreachable!(), - }), - ) + .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_double() { + Ok(Obj::Vector(Vector::Double(v))) => v.into_iter(), + _ => unreachable!(), + })) .collect::>(), ), Vector::Integer(_) => Vector::from( Vec::>::new() .into_iter() - .chain( - vals.values - .into_iter() - .flat_map(|(_, i)| match i.as_integer() { - Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter(), - _ => unreachable!(), - }), - ) + .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_integer() { + Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter(), + _ => unreachable!(), + })) .collect::>(), ), Vector::Logical(_) => Vector::from( Vec::>::new() .into_iter() - .chain( - vals.values - .into_iter() - .flat_map(|(_, i)| match i.as_logical() { - Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter(), - _ => unreachable!(), - }), - ) + .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_logical() { + Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter(), + _ => unreachable!(), + })) .collect::>(), ), }; diff --git a/src/callable/primitive/callstack.rs b/src/callable/primitive/callstack.rs index d30820da..24af6b7d 100644 --- a/src/callable/primitive/callstack.rs +++ b/src/callable/primitive/callstack.rs @@ -40,7 +40,7 @@ impl Callable for PrimitiveCallstack { .frames .iter() .skip(1) // skip global frame - .map(|f| (None, Obj::Expr(f.call.clone()))) + .map(|f| (OptionNA::NA, Obj::Expr(f.call.clone()))) .collect::>(), ))) } diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index dc5e0606..bdc3024f 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -2,6 +2,7 @@ use r_derive::*; use crate::callable::core::*; use crate::lang::*; +use crate::object::types::Character; use crate::object::*; /// Get Names of an Object @@ -70,11 +71,10 @@ impl Callable for PrimitiveNames { Expr(..) => Ok(Null), // handle arg lists? Function(..) => Ok(Null), // return formals? List(x) => { - Ok(x.values - .iter() + Ok(x.iter_pairs() .map(|(k, _)| match k { - Some(name) => OptionNA::Some(name.clone()), - None => OptionNA::NA, // unlike R, unnamed elements are NAs + Character::Some(name) => OptionNA::Some(name.clone()), + OptionNA::NA => OptionNA::NA, // unlike R, unnamed elements are NAs }) .collect::>>() .into()) diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index 6492d8bb..c9dc7e6b 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -3,6 +3,7 @@ use r_derive::*; use crate::callable::core::*; use crate::error::*; use crate::lang::*; +use crate::object::types::Character; use crate::object::*; /// Paste Objects into Strings @@ -65,7 +66,7 @@ impl Callable for PrimitivePaste { // remove named sep and collapse args from our arguments and populate values for (k, v) in args.iter().rev() { - let Some(k) = k else { continue }; + let Character::Some(k) = k else { continue }; match (k.as_str(), v) { ("sep", Obj::Vector(v)) => { diff --git a/src/context/core.rs b/src/context/core.rs index edb1b616..ed48efb9 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -75,34 +75,42 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.values.into_iter()) + Ok(ellipsis.iter_pairs()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(List::new().iter_pairs()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.values.into_iter()) + Ok(more.iter_pairs()) } else { internal_err!() } } // Avoid creating a new closure just to point to another, just reuse it (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { - Ok(c @ Obj::Promise(..)) => Ok(CowObj::from(vec![(k, c)]).into_iter()), - _ => Ok(CowObj::from(vec![( - k, - Obj::Promise(None, Expr::Symbol(s), self.env()), - )]) - .into_iter()), + Ok(c @ Obj::Promise(..)) => { + let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + Ok(List::from(vec![(k, c)]).iter_pairs()) + } + _ => { + let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + Ok(List::from(vec![( + k, + Obj::Promise(None, Expr::Symbol(s), self.env()), + )]) + .iter_pairs()) + } }, (k, c @ Expr::Call(..)) => { + let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); let elem = vec![(k, Obj::Promise(None, c, self.env()))]; - Ok(CowObj::from(elem).into_iter()) + Ok(List::from(elem).iter_pairs()) } (k, v) => { + let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); if let Ok(elem) = self.eval(v) { - Ok(CowObj::from(vec![(k, elem)]).into_iter()) + Ok(List::from(vec![(k, elem)]).iter_pairs()) } else { internal_err!() } @@ -121,20 +129,23 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.values.into_iter()) + Ok(ellipsis.iter_pairs()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(List::from(vec![]).iter_pairs()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.values.into_iter()) + Ok(more.iter_pairs()) } else { - Ok(CowObj::from(vec![]).into_iter()) + Ok(List::from(vec![]).iter_pairs()) } } (k, v) => match self.eval_and_finalize(v) { - Ok(elem) => Ok(CowObj::from(vec![(k, elem)]).into_iter()), + Ok(elem) => { + let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + Ok(List::from(vec![(k, elem)]).iter_pairs()) + } Err(e) => Err(e), }, }) diff --git a/src/lang.rs b/src/lang.rs index 3262aa69..68f8fe2c 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -4,6 +4,7 @@ use crate::context::Context; use crate::error::*; use crate::internal_err; use crate::object::types::*; +use crate::object::List; use crate::object::*; use crate::parser::LocalizedParser; use crate::parser::ParseResult; @@ -69,15 +70,7 @@ impl ViewMut for Obj { Vector::Logical(v) => Vector::Logical(v.view_mut()), }), - Obj::List(List { - names, - values, - subsets, - }) => Obj::List(List { - names: (*names).view_mut(), - values: (*values).view_mut(), - subsets: (*subsets).clone(), - }), + Obj::List(l) => Obj::List(l.view_mut()), // FIXME: this needs to be implemented for all objects that can be mutated x => x.clone(), } diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index d9135c26..0878c3fd 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -41,6 +41,13 @@ impl OptionNA { OptionNA::NA => OptionNA::NA, } } + + pub fn as_option(self) -> Option { + match self { + OptionNA::Some(x) => Option::Some(x), + OptionNA::NA => Option::None, + } + } } #[derive(Debug, PartialEq)] @@ -77,12 +84,23 @@ impl Vector { /// Iterate over the names of the vector. pub fn iter_names(&self) -> Option>>> { + todo!() + // use Vector::*; + // match self { + // Double(x) => x.iter_names(), + // Integer(x) => x.iter_names(), + // Logical(x) => x.iter_names(), + // Character(x) => x.iter_names(), + // } + } + + pub fn is_named(&self) -> bool { use Vector::*; match self { - Double(x) => x.iter_names(), - Integer(x) => x.iter_names(), - Logical(x) => x.iter_names(), - Character(x) => x.iter_names(), + Double(x) => x.is_named(), + Integer(x) => x.is_named(), + Logical(x) => x.is_named(), + Character(x) => x.is_named(), } } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 4037cb28..ba82f6a7 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -126,6 +126,13 @@ where self.0.replace(new_repr); } + pub fn is_named(&self) -> bool { + match self.borrow() { + RepType::Subsets(.., Some(naming)) => true, + _ => false, + } + } + pub fn names(&self) -> Option>> { match self.borrow().clone() { RepType::Subset(_, s, n) => { @@ -163,13 +170,17 @@ where } /// Iterates over owned (name, value) tuples. - pub fn with_iter_pairs(&self, f: F) + pub fn with_iter_pairs(&self, f: F) -> R where F: FnMut(Box>) -> R, { todo!() } + pub fn iter_pairs(&self) -> Box> { + todo!() + } + /// Get immutable access to the internal vector through the passed closure. pub fn with_inner(&self, f: F) -> R where @@ -417,6 +428,15 @@ where } } +impl From, T)>>> for Rep +where + T: Clone + Default, +{ + fn from(rep: CowObj, T)>>) -> Self { + Rep(RefCell::new(rep.into())) + } +} + impl From> for Rep where T: Clone + Default, @@ -442,8 +462,8 @@ where } } -impl From, Obj)>> for Rep<(Option, Obj)> { - fn from(value: Vec<(Option, Obj)>) -> Self { +impl From> for Rep { + fn from(value: Vec<(Character, Obj)>) -> Self { Rep(RefCell::new(value.into())) } } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c561fe34..a93d752f 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -6,9 +6,10 @@ use super::subset::Subset; use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::callable::dyncompare::AsDynCompare; use crate::object::{CowObj, Obj, ViewMut}; use hashbrown::HashMap; +use std::cell::RefCell; +use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Default)] pub struct Naming { @@ -56,6 +57,23 @@ impl Naming { } } +impl From> for RepType { + fn from(value: Vec<(Character, T)>) -> Self { + let mut names = Vec::with_capacity(value.len()); + let mut values = Vec::with_capacity(value.len()); + for (k, v) in value { + names.push(k); + values.push(v); + } + + RepType::Subset( + CowObj::new(Rc::new(RefCell::new(Rc::new(values)))), + Subsets::default(), + Option::Some(Naming::from(names)), + ) + } +} + impl From>> for Naming { fn from(value: CowObj>) -> Self { let mut map: HashMap> = HashMap::new(); @@ -128,10 +146,32 @@ where } } +// FIXME: Don't make this an enum but simply different structs for eah reptype. +// We yield Box anyway. pub enum RepTypeIter { SubsetIter(RepType, usize, usize), } +pub struct RepTypeIterPairs { + x: RepType, + index: usize, + length: usize, +} + +// FIXME: This will be extremely inefficient for Named subsets so optimize this. +impl Iterator for RepTypeIterPairs { + type Item = (Character, T); + fn next(&mut self) -> Option { + if self.index < self.length { + let x = self.x.get_inner_named(self.index); + self.index += 1; + x + } else { + None + } + } +} + impl Iterator for RepTypeIter { type Item = T; fn next(&mut self) -> Option { @@ -240,14 +280,6 @@ impl RepType { todo!() } - /// Iterates over name, value pairs - pub fn with_iter_names(&self, f: F) - where - F: Fn(&Character) -> R, - { - todo!() - } - pub fn with_iter_ref(&self, f: F) where F: FnOnce(&T) -> R, @@ -322,11 +354,16 @@ impl RepType { } } + // FIXME: Do we really need iter_named and iter_pairs? pub fn iter_named<'a>(&'a self) -> Option + 'a>> { let iter_names = self.iter_names()?; Some(Box::new(iter_names.zip(self.iter_values()))) } + pub fn iter_pairs<'a>(&'a self) -> Option + 'a>> { + todo!() + } + // TODO(refactor): This is internal implementation detail and should not be exposed via the API. pub fn iter_subset_indices(&self) -> Box)>> { match self.clone() { @@ -699,13 +736,23 @@ where } } +impl From> for Naming { + fn from(value: Vec) -> Self { + let naming = Naming::new(); + for k in value { + naming.push_name(k); + } + naming + } +} + impl From>> for RepType { fn from(value: CowObj>) -> Self { RepType::Subset(value, Subsets::default(), Option::None) } } -impl From, Obj)>> for RepType<(Option, Obj)> { +impl From, Obj)>> for RepType { fn from(value: Vec<(Option, Obj)>) -> Self { // FIXME: How to handle names? RepType::Subset(value.into(), Subsets::default(), Option::None) From 6d0d17dfb80ed883c5acdf9ca4b58b97486314d7 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 27 Sep 2024 10:54:54 +0530 Subject: [PATCH 14/49] ... --- src/callable/operators.rs | 23 +++++++++++++++++++++++ src/lang.rs | 16 ++++++++++++++-- src/object/vector/rep.rs | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 7e3e84b6..8bef5af0 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -411,6 +411,29 @@ impl Callable for PostfixIndex { let index = stack.eval(x.1)?; what.try_get_inner_mut(index) } + + fn call_assign(&self, value: Expr, args: ExprList, stack: &mut CallStack) -> EvalResult { + let mut argstream = args.into_iter(); + + let Some((_, what)) = argstream.next() else { + unreachable!(); + }; + + let Some((_, name)) = argstream.next() else { + unreachable!(); + }; + + let value = stack.eval(value)?; + let mut what = stack.eval_mut(what)?; + + match name { + Expr::String(s) | Expr::Symbol(s) => { + what.set_named(s.as_str(), value)?; + Ok(what) + } + _ => unimplemented!(), + } + } } #[derive(Debug, Clone, PartialEq)] diff --git a/src/lang.rs b/src/lang.rs index 68f8fe2c..d3787e38 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -94,6 +94,13 @@ impl Obj { } } + // For [[-assignment. + // e.g. list(list(1, 2))[[1]] = list(2) should not be vectorized. + + pub fn replace(&self, value: Obj) -> EvalResult { + todo!() + } + pub fn assign(self, value: Obj) -> EvalResult { // TODO(ERROR) cleanup let err = Error::Other("Invalid target for assignment".to_string()); @@ -104,8 +111,13 @@ impl Obj { Ok(value) } Obj::List(mut l) => { - l.assign(value.clone())?; - Ok(value) + // + if let Obj::List(x) = value.clone() { + l.assign(x); + Ok(value) + } else { + Err(err.into()) + } } _ => Err(err.into()), } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index ba82f6a7..aeb396c7 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -261,6 +261,8 @@ where pub fn assign(&mut self, value: Self) -> Self { // TODO: Handle names here + // The assign method from List had a lot more code, + // check that everything is covered here. self.0.borrow_mut().assign(value.0.into_inner()).into() } /// Test the mode of the internal vector type From 12d5e85691195a380f2673cc375a25cdb84e5691 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 27 Sep 2024 14:46:51 +0530 Subject: [PATCH 15/49] ... --- src/callable/operators.rs | 13 ++-- src/context/core.rs | 5 +- src/lang.rs | 111 +++++++++++++++++------------------ src/object/core.rs | 4 +- src/object/environment.rs | 14 ++--- src/object/vector/core.rs | 5 ++ src/object/vector/rep.rs | 36 ++++++++---- src/object/vector/reptype.rs | 14 +++-- src/object/vector/subset.rs | 23 +++++++- 9 files changed, 126 insertions(+), 99 deletions(-) diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 8bef5af0..7ad94de0 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -419,20 +419,15 @@ impl Callable for PostfixIndex { unreachable!(); }; - let Some((_, name)) = argstream.next() else { + let Some((_, index)) = argstream.next() else { unreachable!(); }; let value = stack.eval(value)?; - let mut what = stack.eval_mut(what)?; + let index = stack.eval(index)?; + let what = stack.eval_mut(what)?.try_get_inner_mut(index)?; - match name { - Expr::String(s) | Expr::Symbol(s) => { - what.set_named(s.as_str(), value)?; - Ok(what) - } - _ => unimplemented!(), - } + what.replace(value) } } diff --git a/src/context/core.rs b/src/context/core.rs index ed48efb9..5da9ac2e 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use crate::lang::{EvalResult, Signal}; +use crate::object::types::Character; use crate::object::*; use crate::{error::*, internal_err}; @@ -131,14 +132,14 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { Ok(ellipsis.iter_pairs()) } else { - Ok(List::from(vec![]).iter_pairs()) + Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { Ok(more.iter_pairs()) } else { - Ok(List::from(vec![]).iter_pairs()) + Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) } } (k, v) => match self.eval_and_finalize(v) { diff --git a/src/lang.rs b/src/lang.rs index d3787e38..88939391 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -3,6 +3,7 @@ use crate::cli::Experiment; use crate::context::Context; use crate::error::*; use crate::internal_err; +use crate::object::rep::Rep; use crate::object::types::*; use crate::object::List; use crate::object::*; @@ -94,11 +95,19 @@ impl Obj { } } - // For [[-assignment. - // e.g. list(list(1, 2))[[1]] = list(2) should not be vectorized. - pub fn replace(&self, value: Obj) -> EvalResult { todo!() + // For [[-assignment. + // e.g. list(list(1, 2))[[1]] = list(2) should not be vectorized. + // use crate::object::Vector; + // match (self, value) { + // (Obj::List(l), r) => l.replace(r), + // (Obj::Vector(l), Obj::Vector(r)) => match (l, r) { + // (Double(l), Double(r)) => todo!(), + // }, + // _ => unimplemented!(), + // } + // self } pub fn assign(self, value: Obj) -> EvalResult { @@ -125,7 +134,7 @@ impl Obj { pub fn as_list(&self) -> EvalResult { match self { - Obj::Null => Ok(Obj::List(List::from(vec![]))), + Obj::Null => Ok(Obj::List(List::new())), Obj::Vector(_v) => internal_err!(), Obj::List(l) => Ok(Obj::List(l.clone())), Obj::Expr(e) => match e { @@ -221,8 +230,8 @@ impl Obj { pub fn get(&self, index: usize) -> Option { match self { Obj::Vector(v) => v.get(index).map(Obj::Vector), + Obj::List(v) => v.get(index).map(Obj::List), Obj::Null => None, - Obj::List(l) => l.values.borrow().get(index).map(|x| x.1.clone()), Obj::Expr(..) => None, Obj::Promise(..) => None, Obj::Function(..) => None, @@ -233,9 +242,8 @@ impl Obj { pub fn get_named(&mut self, name: &str) -> Option { match self { Obj::List(v) => v - .values - .iter() - .find(|(k, _)| *k == Some(String::from(name))) + .iter_pairs() + .find(|(k, _)| *k == Character::Some(String::from(name))) .map(|(_, v)| v.clone()), Obj::Environment(e) => match e.get(String::from(name)) { Ok(v) => Some(v), @@ -246,28 +254,30 @@ impl Obj { } pub fn set_named(&mut self, name: &str, value: Obj) -> EvalResult { - match self { - Obj::List(v) => { - let loc = v - .values - .iter() - .enumerate() - .find(|(_, (k, _))| *k == Some(name.into())) - .map(|(i, _)| i); - - v.values.with_inner_mut(|vb| match loc { - Some(i) => vb[i].1 = value.clone(), - None => vb.push((Some(name.into()), value.clone())), - }); - - Ok(value) - } - Obj::Environment(e) => { - e.values.borrow_mut().insert(name.into(), value.clone()); - Ok(value) - } - _ => Ok(Obj::Null), - } + todo!() + // I feel this is implemented twice + // because we have l[["a"]] = 1 and l$a = 1; + // match self { + // Obj::List(v) => { + // let loc = v + // .iter_pairs() + // .enumerate() + // .find(|(_, (k, _))| *k == Character::Some(name.into())) + // .map(|(i, _)| i); + + // v.with_inner_mut(|vb| match loc { + // Some(i) => vb[i].1 = value.clone(), + // None => vb.push((Some(name.into()), value.clone())), + // }); + + // Ok(value) + // } + // Obj::Environment(e) => { + // e.values.borrow_mut().insert(name.into(), value.clone()); + // Ok(value) + // } + // _ => Ok(Obj::Null), + // } } pub fn environment(&self) -> Option> { @@ -288,9 +298,14 @@ impl Obj { // Used for [ ] syntax pub fn try_get(&self, index: Obj) -> EvalResult { + let index = index.as_vector()?; match self { Obj::Vector(v) => v.try_get(index), - Obj::List(l) => l.try_get(index), + Obj::List(l) => { + let subset = Subset::try_from(index)?; + let x = l.subset(subset); + EvalResult::Ok(Obj::List(List::from(x))) + } obj => obj.as_list()?.try_get(index), } } @@ -298,8 +313,8 @@ impl Obj { // Used for [[ ]] syntax pub fn try_get_inner(&self, index: Obj) -> EvalResult { match self { - Obj::Vector(v) => v.try_get(index), - Obj::List(l) => l.try_get_inner(index), + Obj::Vector(v) => v.try_get_inner(index), + Obj::List(l) => EvalResult::Ok(l.try_get_inner(index.try_into()?)?), obj => obj.as_list()?.try_get_inner(index), } } @@ -308,7 +323,7 @@ impl Obj { pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { match self { Obj::Vector(v) => v.try_get(index), - Obj::List(l) => l.try_get_inner_mut(index), + Obj::List(l) => EvalResult::Ok(l.try_get_inner_mut(index.try_into()?)?), obj => obj.as_list()?.try_get_inner_mut(index), } } @@ -379,29 +394,12 @@ impl Display for Obj { } fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt::Result { - let v = x.values.borrow(); - let s = x.subsets.clone(); - - for (i, (_, si)) in s - .bind_names(x.names.clone()) - .into_iter() - .take(v.len()) - .enumerate() - { - let name; - let value; - - if let Some(i) = si { - (name, value) = v[i].clone(); - } else { - return write!(f, "{}", Obj::Null); - } - + for (i, (maybe_name, value)) in x.iter_pairs().enumerate() { if i > 0 { writeln!(f)? } - let bc_elem = if let Some(name) = name { + let bc_elem = if let Character::Some(name) = maybe_name { format!("${}", name) } else { format!("[[{}]]", i + 1) @@ -838,14 +836,15 @@ impl Context for CallStack { match item { (None, Expr::String(s) | Expr::Symbol(s)) => { let index = Obj::Vector(Vector::from(vec![i])); - let value = args.try_get_inner(index)?; + let value = args.try_get_inner(index.try_into()?)?; self.assign(Expr::Symbol(s), value)?; i += 1; } // TODO(feature): allow arbitrary right-side expressions // evaluated with list as additional data-frame (Some(n), Expr::String(s) | Expr::Symbol(s)) => { - let value = args.try_get_inner(Obj::Vector(Vector::from(vec![s])))?; + let value = + args.try_get_inner(Obj::Vector(Vector::from(vec![s])).try_into()?)?; self.assign(Expr::Symbol(n), value)?; } _ => return internal_err!(), @@ -1081,7 +1080,7 @@ impl Context for Obj { fn get(&mut self, name: String) -> EvalResult { match self { - Obj::List(l) => l.try_get_inner(Obj::Vector(Vector::from(vec![name]))), + Obj::List(l) => Ok(l.try_get_inner(Obj::Vector(Vector::from(vec![name])).try_into()?)?), Obj::Environment(e) => e.get(name), _ => unimplemented!(), } diff --git a/src/object/core.rs b/src/object/core.rs index bc5906ef..c8f6799a 100644 --- a/src/object/core.rs +++ b/src/object/core.rs @@ -26,8 +26,8 @@ impl PartialEq for Obj { match (self, other) { (Obj::Null, Obj::Null) => true, (Obj::List(l), Obj::List(r)) => { - let liter = l.values.iter(); - let riter = r.values.iter(); + let liter = l.iter_pairs(); + let riter = r.iter_pairs(); liter .zip(riter) .all(|((lk, lv), (rk, rv))| lk == rk && lv == rv) diff --git a/src/object/environment.rs b/src/object/environment.rs index e2d2ee05..904b98ed 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -8,6 +8,7 @@ use crate::callable::builtins::BUILTIN; use crate::context::Context; use crate::error::Error; use crate::lang::{EvalResult, Signal}; +use crate::object::types::Character; use crate::object::ViewMut; use super::{Expr, ExprList, List, Obj}; @@ -55,18 +56,11 @@ impl Environment { } pub fn append(&self, l: List) { - let iter = l.iter_pairs(); - - if let Some(iter) { - for (key, value) in l.iter_paier { - if let Some(name) = key { - self.values.borrow_mut().insert(name.clone(), value.clone()); - } + for (key, value) in l.iter_pairs() { + if let Character::Some(name) = key { + self.values.borrow_mut().insert(name.clone(), value.clone()); } - } - - } pub fn get(&self, name: String) -> EvalResult { diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 0878c3fd..c03961fa 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -60,6 +60,9 @@ pub enum Vector { // Raw(Raw), } +// TODO: Implement vector more like Rep +// I.e. the conversion from and to objects should be handled via TryFrom/From +// and .into() calls impl Clone for Vector { fn clone(&self) -> Self { match self { @@ -71,6 +74,8 @@ impl Clone for Vector { } } +// TODO: Ensure that Vector API does not go beyond Rep unless it is really +// necessary. impl Vector { pub fn get(&self, index: usize) -> Option { use Vector::*; diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index aeb396c7..a50b8d4a 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -87,6 +87,15 @@ where self.0.borrow_mut() } + pub fn replace(&self, value: Self) { + // if we do + // l = list(new.env()) + // l[[1]] = list(99) + // we need to replace list(1, 2) with list(99) + let x = value.0.into_inner(); + self.0.replace(x); + } + /// Iterate over the (owned) values of the vector. // pub fn iter_values(&self) -> Box + '_> { // let x = self.0.borrow().clone(); @@ -127,8 +136,8 @@ where } pub fn is_named(&self) -> bool { - match self.borrow() { - RepType::Subsets(.., Some(naming)) => true, + match self.borrow().clone() { + RepType::Subset(.., Some(_)) => true, _ => false, } } @@ -178,6 +187,7 @@ where } pub fn iter_pairs(&self) -> Box> { + // FIXME: This should probably return an Option where None is returned in case there are no names. todo!() } @@ -251,8 +261,11 @@ where self.borrow().get_inner_named(index) } - pub fn push(&self, value: T) { - self.borrow().push(value) + pub fn values(&self) -> CowObj> { + self.materialize_inplace(); + match self.0.borrow().clone() { + RepType::Subset(values, ..) => values, + } } pub fn push_named(&self, name: OptionNA, value: T) { @@ -430,15 +443,6 @@ where } } -impl From, T)>>> for Rep -where - T: Clone + Default, -{ - fn from(rep: CowObj, T)>>) -> Self { - Rep(RefCell::new(rep.into())) - } -} - impl From> for Rep where T: Clone + Default, @@ -518,6 +522,12 @@ impl From> for Rep { } } +impl From, T)>> for Rep { + fn from(value: Vec<(Option, T)>) -> Self { + Rep(RefCell::new(value.into())) + } +} + impl Display for Rep where T: AtomicMode + Debug + Default + Clone, diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index a93d752f..9dfdb5c8 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -752,10 +752,16 @@ impl From>> for RepType { } } -impl From, Obj)>> for RepType { - fn from(value: Vec<(Option, Obj)>) -> Self { - // FIXME: How to handle names? - RepType::Subset(value.into(), Subsets::default(), Option::None) +impl From, T)>> for RepType { + fn from(value: Vec<(Option, T)>) -> Self { + let mut names = Vec::with_capacity(value.len()); + let mut values = Vec::with_capacity(value.len()); + for (k, v) in value.into_iter() { + names.push(k.map_or(Character::NA, |x| Character::Some(x))); + values.push(v) + } + let naming = Naming::from(names); + RepType::Subset(values.into(), Subsets::default(), Some(naming)) } } diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index 333842e5..f4a00833 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -2,10 +2,10 @@ use std::cell::RefCell; use std::ops::Range; use std::rc::Rc; -use crate::lang::Signal; -use crate::object::CowObj; - use super::{types::*, OptionNA, Vector}; +use crate::error::Error; +use crate::lang::Signal; +use crate::object::{CowObj, Obj}; /// Subsets /// @@ -187,6 +187,23 @@ impl Subset { } } +impl TryFrom for Subset { + type Error = Signal; + fn try_from(value: Obj) -> Result { + use crate::object::Vector; + let err = Error::Other("Cannot use object for indexing".to_string()); + match value.as_vector()? { + Obj::Vector(v) => match v { + Vector::Double(x) => unimplemented!(), + Vector::Integer(x) => Ok(Subset::Indices(x.values())), + Vector::Character(x) => Ok(Subset::Names(x.values())), + Vector::Logical(x) => Ok(Subset::Mask(x.values())), + }, + _ => err.into(), + } + } +} + impl From for Subset { fn from(value: usize) -> Self { Subset::Indices(vec![OptionNA::Some(value as i32)].into()) From 41b3dc2677898e9da11ce158f5cdf8de5489b7df Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Fri, 27 Sep 2024 18:09:55 +0530 Subject: [PATCH 16/49] ... --- src/object/cow.rs | 4 ++ src/object/vector/rep.rs | 27 ++++++++++++-- src/object/vector/reptype.rs | 72 +++++++++++++++++++++++++++--------- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/src/object/cow.rs b/src/object/cow.rs index 3a2b5b2a..f8222c66 100644 --- a/src/object/cow.rs +++ b/src/object/cow.rs @@ -59,6 +59,10 @@ impl CowObj { CowObj(x) } + pub fn inner_rc(&self) -> Rc { + self.borrow().clone() + } + /// Get mutable access to the internal vector. /// In case more than one reference to the internal data exists, /// the vector is cloned. diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index a50b8d4a..37ae390b 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -11,6 +11,8 @@ use super::{OptionNA, Pow, VecPartialCmp}; use crate::error::Error; use crate::object::{CowObj, Obj, ViewMut}; +use crate::object::reptype::RepTypeSubsetIterPairs; + /// Vector Representation /// /// The ref-cell is used so vectors can change there internal representation, @@ -186,9 +188,28 @@ where todo!() } - pub fn iter_pairs(&self) -> Box> { - // FIXME: This should probably return an Option where None is returned in case there are no names. - todo!() + // pub fn into_iter_pairs(self) -> Box + '_> { + // self.clone().iter_pairs() + // } + + pub fn iter_pairs(&self) -> RepTypeSubsetIterPairs { + let x = self.borrow().clone(); + + match x.clone() { + RepType::Subset(values, _, maybe_naming) => { + let index_iter = x.iter_subset_indices().map(|(_, i)| i); + let names = maybe_naming.map(|x| x.names.inner_rc()); + + RepTypeSubsetIterPairs { + values: values.inner_rc(), + names, + iter: Box::new(index_iter), + } + } + } + // // FIXME: This should probably return an Option where None is returned in case there are no names. + // let x = self.borrow().clone(); + // x.iter_pairs() } /// Get immutable access to the internal vector through the passed closure. diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 9dfdb5c8..4aa032b1 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -146,32 +146,56 @@ where } } -// FIXME: Don't make this an enum but simply different structs for eah reptype. -// We yield Box anyway. -pub enum RepTypeIter { - SubsetIter(RepType, usize, usize), +pub struct RepTypeSubsetIterPairs { + pub values: Rc>, + pub names: Option>>, + pub iter: Box>>, } -pub struct RepTypeIterPairs { - x: RepType, - index: usize, - length: usize, +pub struct RepTypeSubsetIterPairsRef<'a, T: Clone> { + values: &'a Rc>, + names: &'a Rc>, + na: &'a T, + iter: Box>>, } -// FIXME: This will be extremely inefficient for Named subsets so optimize this. -impl Iterator for RepTypeIterPairs { +impl Iterator for RepTypeSubsetIterPairs { type Item = (Character, T); fn next(&mut self) -> Option { - if self.index < self.length { - let x = self.x.get_inner_named(self.index); - self.index += 1; - x + let maybe_index = self.iter.next()?; + if let Some(index) = maybe_index { + println!("hiii: {}", index); + let value = self.values[index].clone(); + // Option::Some((self.names[index].clone(), self.values[index].clone())) + if let Some(names) = &self.names { + Option::Some((names[index].clone(), value)) + } else { + Option::Some((Character::NA, value)) + } + } else { + Option::Some((Character::NA, T::default())) + } + } +} + +impl<'a, T: Clone + Default> Iterator for RepTypeSubsetIterPairsRef<'a, T> { + type Item = (&'a OptionNA, &'a T); + fn next(&mut self) -> Option { + let maybe_index = self.iter.next()?; + if let Some(index) = maybe_index { + Option::Some((&self.names[index], &self.values[index])) } else { - None + Option::Some((&OptionNA::NA, self.na)) } } } +// FIXME: Don't make this an enum but simply different structs for eah reptype. +// We yield Box anyway. +pub enum RepTypeIter { + SubsetIter(RepType, usize, usize), +} + impl Iterator for RepTypeIter { type Item = T; fn next(&mut self) -> Option { @@ -360,14 +384,26 @@ impl RepType { Some(Box::new(iter_names.zip(self.iter_values()))) } - pub fn iter_pairs<'a>(&'a self) -> Option + 'a>> { - todo!() + // TODO: this should not be used so much. Instead we should iterate over references. + pub fn iter_pairs<'a>(&'a self) -> Box + 'a> { + match self.clone() { + RepType::Subset(values, _, maybe_naming) => { + let index_iter = self.iter_subset_indices().map(|(_, i)| i); + let names = maybe_naming.map(|x| x.names.inner_rc()); + + Box::new(RepTypeSubsetIterPairs { + values: values.inner_rc(), + names, + iter: Box::new(index_iter), + }) + } + } } - // TODO(refactor): This is internal implementation detail and should not be exposed via the API. pub fn iter_subset_indices(&self) -> Box)>> { match self.clone() { RepType::Subset(_, subsets, Some(naming)) => { + println!("du"); Box::new(subsets.bind_names(naming.map).into_iter()) } RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), From 22ed4bcd99728d02c0c04ec998f8eeed9b4d9d41 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 28 Sep 2024 12:02:06 +0530 Subject: [PATCH 17/49] ... --- src/callable/core.rs | 21 ++------ src/callable/primitive/c.rs | 96 +++++++++++++++------------------ src/object/vector/rep.rs | 61 ++++++++++++++++----- src/object/vector/reptype.rs | 102 ++++++++++++++++++++++++----------- src/object/vector/subset.rs | 11 ++-- src/object/vector/subsets.rs | 17 ++++++ 6 files changed, 191 insertions(+), 117 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 2616d8e7..7f32344f 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -81,8 +81,7 @@ pub trait Callable { // remove any Ellipsis param, and any trailing unassigned params let remainder = formals.pop_trailing(); - // backfill unnamed args, populating ellipsis with overflow - args.with_pairs(|key, value| { + for (key, value) in args.iter_pairs() { match key { // named args go directly to ellipsis, they did not match a formal Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value), @@ -97,7 +96,7 @@ pub trait Callable { } } } - }); + } // add back in parameter defaults that weren't filled with args for (param, default) in formals.into_iter() { @@ -296,24 +295,12 @@ impl TryFrom<&str> for Box { pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. - let x = vals.with_iter_pairs(|iter| { - iter.map(|(k, v)| match (k, v.force(stack)) { + vals.iter_pairs() + .map(|(k, v)| match (k, v.force(stack)) { (k, Ok(v)) => Ok((k, v)), (_, Err(e)) => Err(e), }) .collect() - }); - x - - // vals.with_iter_pairs(|k, v| { - // (k, Ok(v)) => Ok((k, v)), - // (_, Err(e)) => Err(e), - // }) - // vals.values - // .into_iter() - // .map(|(k, v)| match (k, v.force(stack)) { - // }) - // .collect() } impl Format for String { diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index c3e35e3d..d2cf4a4f 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -51,28 +51,26 @@ impl Callable for PrimitiveC { }; // lets first see what we're aiming to build. - let ty: u8 = vals.with_iter_pairs(|iter| { - iter.map(|(_, v)| match v { + let ty: u8 = vals + .iter_pairs() + .map(|(_, v)| match v { Obj::Null => 0, Obj::Vector(_) => 1, Obj::List(_) => 2, _ => 0, }) - .fold(0, std::cmp::max) - }); + .fold(0, std::cmp::max); // if the output will have names - let named = vals.with_iter_pairs(|mut iter| { - iter.any(|(n, o)| { - if matches!(n, OptionNA::Some(_)) { - return true; - } - match o { - Obj::Vector(v) => v.is_named(), - Obj::List(l) => l.is_named(), - _ => todo!(), - } - }) + let named = vals.iter_pairs().any(|(n, o)| { + if matches!(n, OptionNA::Some(_)) { + return true; + } + match o { + Obj::Vector(v) => v.is_named(), + Obj::List(l) => l.is_named(), + _ => todo!(), + } }); // most complex type was NULL @@ -87,49 +85,44 @@ impl Callable for PrimitiveC { } let names: Option> = if named { - let nms = vals.with_iter_pairs(|iter| { - iter.flat_map(|(name, obj)| { - let maybe_prefix = name - .as_option() - .as_ref() - .and_then(|n| Option::Some(n.clone())); + let nms = vals.iter_pairs().flat_map(|(name, obj)| { + let maybe_prefix = name + .as_option() + .as_ref() + .and_then(|n| Option::Some(n.clone())); - if let Obj::Vector(v) = obj { - let maybe_names_iter = v.iter_names(); + if let Obj::Vector(v) = obj { + let maybe_names_iter = v.iter_names(); - let x: Vec = match (maybe_prefix, maybe_names_iter) { - (None, None) => { - std::iter::repeat(Character::NA).take(v.len()).collect() - } - (Some(prefix), None) => { - std::iter::repeat(Character::Some(prefix.clone())) - .take(v.len()) - .collect() - } - (None, Some(names_iter)) => names_iter.collect(), - (Some(prefix), Some(names_iter)) => names_iter - .map(|maybe_name| { - if let OptionNA::Some(name) = maybe_name { - Character::Some(format!("{}.{}", prefix, name)) - } else { - Character::Some(prefix.clone()) - } - }) - .collect(), - }; - x - } else { - unimplemented!() - } - }) + let x: Vec = match (maybe_prefix, maybe_names_iter) { + (None, None) => std::iter::repeat(Character::NA).take(v.len()).collect(), + (Some(prefix), None) => std::iter::repeat(Character::Some(prefix.clone())) + .take(v.len()) + .collect(), + (None, Some(names_iter)) => names_iter.collect(), + (Some(prefix), Some(names_iter)) => names_iter + .map(|maybe_name| { + if let OptionNA::Some(name) = maybe_name { + Character::Some(format!("{}.{}", prefix, name)) + } else { + Character::Some(prefix.clone()) + } + }) + .collect(), + }; + x + } else { + unimplemented!() + } }); Some(nms.collect()) } else { None }; - let ret = vals.with_iter_pairs(|iter| { - iter.map(|(_, r)| match r { + let ret = vals + .iter_pairs() + .map(|(_, r)| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Integer(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Double(_)) => Vector::from(Vec::::new()), @@ -144,8 +137,7 @@ impl Callable for PrimitiveC { (v @ Vector::Integer(_), _) => v, (_, v @ Vector::Integer(_)) => v, (v @ Vector::Logical(_), _) => v, - }) - }); + }); // consume values and merge into a new collection let v = match ret { diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 37ae390b..00cc3352 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -3,12 +3,13 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::RepType; -use super::reptype::RepTypeIter; +use super::reptype::{Naming, RepType}; +use super::reptype::{RepTypeIter, RepTypeSubsetIterPairsRef}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::error::Error; +use crate::object::Subsets; use crate::object::{CowObj, Obj, ViewMut}; use crate::object::reptype::RepTypeSubsetIterPairs; @@ -164,6 +165,20 @@ where self.0.into_inner().dedup_last().into() } + /// Preallocates a + pub fn with_capacity(n: usize, names: bool) -> Self { + let naming = if names { + Some(Naming::with_capacity(n)) + } else { + None + }; + Self(RefCell::new(RepType::Subset( + CowObj::from(Vec::with_capacity(n)), + Subsets::default(), + naming, + ))) + } + /// Get mutable access to the internal vector through the passed closure. pub fn with_inner_mut(&self, f: F) -> R where @@ -188,10 +203,6 @@ where todo!() } - // pub fn into_iter_pairs(self) -> Box + '_> { - // self.clone().iter_pairs() - // } - pub fn iter_pairs(&self) -> RepTypeSubsetIterPairs { let x = self.borrow().clone(); @@ -212,13 +223,36 @@ where // x.iter_pairs() } - /// Get immutable access to the internal vector through the passed closure. - pub fn with_inner(&self, f: F) -> R - where - F: FnOnce(&Vec) -> R, - { - self.0.borrow().with_inner(f) - } + // pub fn iter_subset_indices(&self) -> Box)>> { + // todo!() + // } + + // /// Iterate over mutable references to the values of the vector by passing a closure. + // /// The current subsets of the vector are represented. + // /// This method should be used for vectorized assignment. + // /// + // /// It is + // /// Due to the complex structure of this struct it is not possible to return an iterator that yields + // /// mutable references to the values of the struct. + // pub fn with_iter_pairs_mut_ref<'a, F, R>(&'a self, f: F) -> R + // where + // F: FnMut(&mut [T], Option<&mut [Character]>, Box>>) -> R, + // { + // // We cannot easily get an Iterator that yields &mut T, even through a closure. + // // This is because we might iterate over the same value multiple times (consider a subset x[c(1, 1)]) + // // two consecutive calls to .next() might yield the same mutable reference which is illegal. + // // Instead we give acces to &mut [T] and &mut [Character] and the index iterator + // // + // // Maybe this is possible somehow but I am not sure how to satisfy the rust compiler. + + // when we cannot ensure that each index + // for x in self.iter_mut() {} + // // FIXME: This is impossible I think. + // // It would be possible to pass a closure that receives |&mut T| + // // FIXME: I don't think this would be + // let iter = todo!(); + // f(iter) + // } pub fn materialize(&self) -> Self { self.borrow().materialize().into() @@ -279,6 +313,7 @@ where } pub fn get_inner_named(&self, index: usize) -> Option<(Character, T)> { + // TODO: I don't think this is really needed. self.borrow().get_inner_named(index) } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 4aa032b1..dbea664c 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -23,6 +23,13 @@ impl Naming { Naming::default() } + pub fn with_capacity(n: usize) -> Self { + Self { + map: HashMap::>::with_capacity(n).into(), + names: CowObj::from(Vec::::with_capacity(n)), + } + } + pub fn remove(&self, index: usize) -> Character { // FIXME: Already assumes names are unique let maybe_name = self.names.with_inner_mut(|names| names.remove(index)); @@ -131,6 +138,7 @@ impl RepType { } } +// TODO: Remove this it is stupid impl IntoIterator for RepType where T: Clone + Default, @@ -146,6 +154,7 @@ where } } +/// TODO: probably also remove this because we should usually iterate over references and we can then call .map(|(a, b)| (a.clone(), b.clone())) if we need to. pub struct RepTypeSubsetIterPairs { pub values: Rc>, pub names: Option>>, @@ -153,39 +162,51 @@ pub struct RepTypeSubsetIterPairs { } pub struct RepTypeSubsetIterPairsRef<'a, T: Clone> { - values: &'a Rc>, - names: &'a Rc>, + values: &'a [T], + names: Option<&'a [Character]>, + // this should be the default value. + // In the future when we don't allow subsetting with NAs anymore this should become irrelevant. + // we need this because when the iter iterator below yields Option::None we need to return NA. na: &'a T, iter: Box>>, } -impl Iterator for RepTypeSubsetIterPairs { - type Item = (Character, T); +impl<'a, T: Clone> Iterator for RepTypeSubsetIterPairsRef<'a, T> { + type Item = (&'a Character, &'a T); fn next(&mut self) -> Option { + // None represents NA, will be removed in the future I think. let maybe_index = self.iter.next()?; + if let Some(index) = maybe_index { println!("hiii: {}", index); - let value = self.values[index].clone(); - // Option::Some((self.names[index].clone(), self.values[index].clone())) + let value = &self.values[index]; + if let Some(names) = &self.names { - Option::Some((names[index].clone(), value)) + Option::Some((&names[index], value)) } else { - Option::Some((Character::NA, value)) + Option::Some((&Character::NA, value)) } } else { - Option::Some((Character::NA, T::default())) + panic!() + // Option::Some((&Character::NA, self.na)) } } } -impl<'a, T: Clone + Default> Iterator for RepTypeSubsetIterPairsRef<'a, T> { - type Item = (&'a OptionNA, &'a T); +impl Iterator for RepTypeSubsetIterPairs { + type Item = (Character, T); fn next(&mut self) -> Option { let maybe_index = self.iter.next()?; if let Some(index) = maybe_index { - Option::Some((&self.names[index], &self.values[index])) + let value = self.values[index].clone(); + // Option::Some((self.names[index].clone(), self.values[index].clone())) + if let Some(names) = &self.names { + Option::Some((names[index].clone(), value)) + } else { + Option::Some((Character::NA, value)) + } } else { - Option::Some((&OptionNA::NA, self.na)) + Option::Some((Character::NA, T::default())) } } } @@ -248,22 +269,10 @@ impl RepType { ) } - /// Preallocates a RepType with the given capacity. - pub fn with_capacity(n: usize) { - todo!() - } - pub fn ensure_named(&self) { todo!() } - pub fn with_iter_pairs(&self, f: F) - where - F: FnMut(Box>) -> R, - { - todo!() - } - /// Iterates over owned (name, value) tuples. pub fn with_pairs(&self, f: F) where @@ -401,12 +410,41 @@ impl RepType { } pub fn iter_subset_indices(&self) -> Box)>> { + // TODO: This function is crucial to fix match self.clone() { - RepType::Subset(_, subsets, Some(naming)) => { - println!("du"); + RepType::Subset(vals, subsets, Some(naming)) => { + let x = vals.borrow().clone(); + + // println!("{}", x.len()); + + // for k in naming.map.borrow().keys() { + // println!("{}", k); + // } + + // for n in naming.names.clone() { + // println!("{}", n); + // } + + // for i in x { + // println("{}", i); + // } + // let iter = subsets.clone().bind_names(naming.map.clone()).into_iter(); + + // for (_, maybe_i) in iter { + // if let Some(i) = maybe_i { + // println!("{}", i); + // } else { + // println!("None"); + // } + // } + + // FIXME: we need to call .take() with the proper n Box::new(subsets.bind_names(naming.map).into_iter()) } - RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), + RepType::Subset(_, subsets, None) => { + println!("BBB"); + Box::new(subsets.into_iter()) + } } } @@ -555,8 +593,6 @@ impl RepType { T: Clone + Default, { // TODO(feature): here we should also throw an error if the recycling rules are violated. - // TODO(refactor): I don't think we should ever iterate over the indices. - // Instead the API of RepType should conveniently, i.e. offer Iterators that yield mutable / immutable references to the Ts. let l_indices = self.iter_subset_indices(); let r_indices = value.iter_subset_indices(); match (self, value) { @@ -729,8 +765,9 @@ impl RepType { pub fn get_inner(&self, index: usize) -> Option { match self { - RepType::Subset(v, subsets, n) => { - if n.is_some() { + RepType::Subset(v, subsets, maybe_naming) => { + if maybe_naming.is_some() { + // TODO(NOW) unimplemented!() } let vb = v.borrow(); @@ -740,6 +777,7 @@ impl RepType { } } pub fn get_inner_named(&self, index: usize) -> Option<(OptionNA, T)> { + // TODO: I don't think this is really needed match &self { RepType::Subset(.., maybe_naming) => { let x = self.get_inner(index)?; diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index f4a00833..0fba760b 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -190,11 +190,16 @@ impl Subset { impl TryFrom for Subset { type Error = Signal; fn try_from(value: Obj) -> Result { - use crate::object::Vector; let err = Error::Other("Cannot use object for indexing".to_string()); - match value.as_vector()? { + match value { Obj::Vector(v) => match v { - Vector::Double(x) => unimplemented!(), + Vector::Double(_) => { + if let Vector::Integer(x) = v.as_integer() { + Ok(Subset::Indices(x.values())) + } else { + unreachable!() + } + } Vector::Integer(x) => Ok(Subset::Indices(x.values())), Vector::Character(x) => Ok(Subset::Names(x.values())), Vector::Logical(x) => Ok(Subset::Mask(x.values())), diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index d6f0b6a8..8b1ca8bf 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -71,8 +71,25 @@ impl IntoIterator for NamedSubsets { type IntoIter = Box>; fn into_iter(self) -> Self::IntoIter { + let n_subsets = self.subsets.len(); + if n_subsets == 0 { + return Box::new((0_usize..n_subsets).map(|(i)| (i, Some(i)))); + } + let mut iter = Box::new((0_usize..).map(|i| (i, Some(i)))) as Self::IntoIter; let Subsets(subsets) = self.subsets; + // Explanation: + // We have a HashMap: String -> Vec + // We start with an Iterator that yields (usize, Option) for 1, ..., n where n is the length + // Each iterator adapts it to (usize, Option) where the first element is the index (1, ..., n_new) and the second the original index + // let's say we do + // l = list(a = 1, b = 2, c = 3) + // l[c(2, 1)][c("b", "a")] which yields list(b = 2, a = 1) + // 1. Iterator gives [(1, Some(2)), (2, Some(1))] + // 2. Iterator: + // 2.1 We find the value for "b". Here we only need to check the names from 1, ..., 2 (the size_hint below) + // 2.2 + for subset in subsets { match subset { Subset::Names(names) => { From 9e129083e03a81db9e70d7c57566d48bd04b1bd6 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 28 Sep 2024 16:17:36 +0530 Subject: [PATCH 18/49] ... --- src/callable/core.rs | 23 +++---- src/callable/primitive/c.rs | 99 ++++++++++++++++------------ src/callable/primitive/names.rs | 3 +- src/context/core.rs | 25 +++---- src/lang.rs | 7 +- src/object/core.rs | 12 ++-- src/object/environment.rs | 2 +- src/object/vector/rep.rs | 24 +------ src/object/vector/reptype.rs | 112 +++++++++++++++----------------- 9 files changed, 148 insertions(+), 159 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 7f32344f..ada51917 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -44,15 +44,8 @@ pub trait Callable { // assign named args to corresponding formals - // What we do here: - // 1. We iterate over the args values, check whether the value is named. - // 2. If this is also a formal, we add it to the matched list. - // 3. Otherwise we keep iterating. - // We need the special 'inner context because we are acessing args.values mutable and immutably. - - // How else can we implement this? - let mut i: usize = 0; + 'outer: while i < args.len() { 'inner: { // check argname with immutable borrow, but drop scope. If @@ -81,18 +74,20 @@ pub trait Callable { // remove any Ellipsis param, and any trailing unassigned params let remainder = formals.pop_trailing(); - for (key, value) in args.iter_pairs() { + for (key, value) in args.pairs().iter() { match key { // named args go directly to ellipsis, they did not match a formal - Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value), + Character::Some(arg) => { + ellipsis.push_named(Character::Some(arg.clone()), value.clone()) + } // unnamed args populate next formal, or ellipsis if formals exhausted Character::NA => { let next_unassigned_formal = formals.remove(0); if let Some((Some(param), _)) = next_unassigned_formal { - matched_args.push_named(Character::Some(param), value); + matched_args.push_named(Character::Some(param), value.clone()); } else { - ellipsis.push_named(Character::NA, value); + ellipsis.push_named(Character::NA, value.clone()); } } } @@ -295,7 +290,9 @@ impl TryFrom<&str> for Box { pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. - vals.iter_pairs() + vals.pairs() + .iter() + .map(|(a, b)| (a.clone(), b.clone())) .map(|(k, v)| match (k, v.force(stack)) { (k, Ok(v)) => Ok((k, v)), (_, Err(e)) => Err(e), diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index d2cf4a4f..6318422e 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -52,7 +52,8 @@ impl Callable for PrimitiveC { // lets first see what we're aiming to build. let ty: u8 = vals - .iter_pairs() + .pairs() + .iter() .map(|(_, v)| match v { Obj::Null => 0, Obj::Vector(_) => 1, @@ -62,7 +63,7 @@ impl Callable for PrimitiveC { .fold(0, std::cmp::max); // if the output will have names - let named = vals.iter_pairs().any(|(n, o)| { + let named = vals.pairs().iter().any(|(n, o)| { if matches!(n, OptionNA::Some(_)) { return true; } @@ -85,8 +86,10 @@ impl Callable for PrimitiveC { } let names: Option> = if named { - let nms = vals.iter_pairs().flat_map(|(name, obj)| { + let mut pairs = vals.pairs(); + let nms = pairs.iter().flat_map(|(name, obj)| { let maybe_prefix = name + .clone() .as_option() .as_ref() .and_then(|n| Option::Some(n.clone())); @@ -121,7 +124,8 @@ impl Callable for PrimitiveC { }; let ret = vals - .iter_pairs() + .pairs() + .iter() .map(|(_, r)| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Integer(_)) => Vector::from(Vec::::new()), @@ -140,44 +144,55 @@ impl Callable for PrimitiveC { }); // consume values and merge into a new collection - let v = match ret { - Vector::Character(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_character() { - Ok(Obj::Vector(Vector::Character(v))) => v.into_iter(), - _ => unreachable!(), - })) - .collect::>(), - ), - Vector::Double(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_double() { - Ok(Obj::Vector(Vector::Double(v))) => v.into_iter(), - _ => unreachable!(), - })) - .collect::>(), - ), - Vector::Integer(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_integer() { - Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter(), - _ => unreachable!(), - })) - .collect::>(), - ), - Vector::Logical(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.iter_pairs().flat_map(|(_, i)| match i.as_logical() { - Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter(), - _ => unreachable!(), - })) - .collect::>(), - ), - }; + let v = + match ret { + Vector::Character(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.pairs().iter().flat_map( + |(_, i)| match i.clone().as_character() { + Ok(Obj::Vector(Vector::Character(v))) => v.into_iter(), + _ => unreachable!(), + }, + )) + .collect::>(), + ), + Vector::Double(_) => { + Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.pairs().iter().flat_map( + |(_, i)| match i.clone().as_double() { + Ok(Obj::Vector(Vector::Double(v))) => v.into_iter(), + _ => unreachable!(), + }, + )) + .collect::>(), + ) + } + Vector::Integer(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.pairs().iter().flat_map( + |(_, i)| match i.clone().as_integer() { + Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter(), + _ => unreachable!(), + }, + )) + .collect::>(), + ), + Vector::Logical(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.pairs().iter().flat_map( + |(_, i)| match i.clone().as_logical() { + Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter(), + _ => unreachable!(), + }, + )) + .collect::>(), + ), + }; if let Some(names) = names { v.set_names_(names.into()) diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index bdc3024f..1041923e 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -71,7 +71,8 @@ impl Callable for PrimitiveNames { Expr(..) => Ok(Null), // handle arg lists? Function(..) => Ok(Null), // return formals? List(x) => { - Ok(x.iter_pairs() + Ok(x.pairs() + .iter() .map(|(k, _)| match k { Character::Some(name) => OptionNA::Some(name.clone()), OptionNA::NA => OptionNA::NA, // unlike R, unnamed elements are NAs diff --git a/src/context/core.rs b/src/context/core.rs index 5da9ac2e..2c611324 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -76,14 +76,14 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.iter_pairs()) + Ok(ellipsis.pairs().iter()) } else { - Ok(List::new().iter_pairs()) + Ok(List::new().pairs().iter()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.iter_pairs()) + Ok(more.pairs().iter()) } else { internal_err!() } @@ -92,7 +92,7 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { Ok(c @ Obj::Promise(..)) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); - Ok(List::from(vec![(k, c)]).iter_pairs()) + Ok(List::from(vec![(k, c)]).pairs().iter()) } _ => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); @@ -100,18 +100,19 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { k, Obj::Promise(None, Expr::Symbol(s), self.env()), )]) - .iter_pairs()) + .pairs() + .iter()) } }, (k, c @ Expr::Call(..)) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); let elem = vec![(k, Obj::Promise(None, c, self.env()))]; - Ok(List::from(elem).iter_pairs()) + Ok(List::from(elem).pairs().iter()) } (k, v) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); if let Ok(elem) = self.eval(v) { - Ok(List::from(vec![(k, elem)]).iter_pairs()) + Ok(List::from(vec![(k, elem)]).pairs().iter()) } else { internal_err!() } @@ -130,22 +131,22 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.iter_pairs()) + Ok(ellipsis.pairs().iter()) } else { - Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) + Ok(List::from(Vec::<(Character, Obj)>::new()).pairs().iter()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.iter_pairs()) + Ok(more.pairs().iter()) } else { - Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) + Ok(List::from(Vec::<(Character, Obj)>::new()).pairs().iter()) } } (k, v) => match self.eval_and_finalize(v) { Ok(elem) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); - Ok(List::from(vec![(k, elem)]).iter_pairs()) + Ok(List::from(vec![(k, elem)]).pairs().iter()) } Err(e) => Err(e), }, diff --git a/src/lang.rs b/src/lang.rs index 88939391..f20135d7 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -242,8 +242,9 @@ impl Obj { pub fn get_named(&mut self, name: &str) -> Option { match self { Obj::List(v) => v - .iter_pairs() - .find(|(k, _)| *k == Character::Some(String::from(name))) + .pairs() + .iter() + .find(|(k, _)| *k == &Character::Some(String::from(name))) .map(|(_, v)| v.clone()), Obj::Environment(e) => match e.get(String::from(name)) { Ok(v) => Some(v), @@ -394,7 +395,7 @@ impl Display for Obj { } fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt::Result { - for (i, (maybe_name, value)) in x.iter_pairs().enumerate() { + for (i, (maybe_name, value)) in x.pairs().iter().enumerate() { if i > 0 { writeln!(f)? } diff --git a/src/object/core.rs b/src/object/core.rs index c8f6799a..ea7607fd 100644 --- a/src/object/core.rs +++ b/src/object/core.rs @@ -25,13 +25,11 @@ impl PartialEq for Obj { fn eq(&self, other: &Self) -> bool { match (self, other) { (Obj::Null, Obj::Null) => true, - (Obj::List(l), Obj::List(r)) => { - let liter = l.iter_pairs(); - let riter = r.iter_pairs(); - liter - .zip(riter) - .all(|((lk, lv), (rk, rv))| lk == rk && lv == rv) - } + (Obj::List(l), Obj::List(r)) => l + .pairs() + .iter() + .zip(r.pairs().iter()) + .all(|((lk, lv), (rk, rv))| lk == rk && lv == rv), (Obj::Expr(l), Obj::Expr(r)) => l == r, (Obj::Promise(None, lc, lenv), Obj::Promise(None, rc, renv)) => { lc == rc && lenv == renv diff --git a/src/object/environment.rs b/src/object/environment.rs index 904b98ed..71ecc05d 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -56,7 +56,7 @@ impl Environment { } pub fn append(&self, l: List) { - for (key, value) in l.iter_pairs() { + for (key, value) in l.pairs().iter() { if let Character::Some(name) = key { self.values.borrow_mut().insert(name.clone(), value.clone()); } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 00cc3352..a1115380 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -4,7 +4,7 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; use super::reptype::{Naming, RepType}; -use super::reptype::{RepTypeIter, RepTypeSubsetIterPairsRef}; +use super::reptype::{RepTypeIntoIterable, RepTypeIter}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; @@ -12,8 +12,6 @@ use crate::error::Error; use crate::object::Subsets; use crate::object::{CowObj, Obj, ViewMut}; -use crate::object::reptype::RepTypeSubsetIterPairs; - /// Vector Representation /// /// The ref-cell is used so vectors can change there internal representation, @@ -203,24 +201,8 @@ where todo!() } - pub fn iter_pairs(&self) -> RepTypeSubsetIterPairs { - let x = self.borrow().clone(); - - match x.clone() { - RepType::Subset(values, _, maybe_naming) => { - let index_iter = x.iter_subset_indices().map(|(_, i)| i); - let names = maybe_naming.map(|x| x.names.inner_rc()); - - RepTypeSubsetIterPairs { - values: values.inner_rc(), - names, - iter: Box::new(index_iter), - } - } - } - // // FIXME: This should probably return an Option where None is returned in case there are no names. - // let x = self.borrow().clone(); - // x.iter_pairs() + pub fn pairs(&self) -> RepTypeIntoIterable { + self.0.borrow().iterable() } // pub fn iter_subset_indices(&self) -> Box)>> { diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index dbea664c..ae12edbd 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -154,60 +154,52 @@ where } } -/// TODO: probably also remove this because we should usually iterate over references and we can then call .map(|(a, b)| (a.clone(), b.clone())) if we need to. -pub struct RepTypeSubsetIterPairs { - pub values: Rc>, - pub names: Option>>, - pub iter: Box>>, -} - -pub struct RepTypeSubsetIterPairsRef<'a, T: Clone> { - values: &'a [T], - names: Option<&'a [Character]>, - // this should be the default value. - // In the future when we don't allow subsetting with NAs anymore this should become irrelevant. - // we need this because when the iter iterator below yields Option::None we need to return NA. - na: &'a T, +pub struct RepTypeIntoIterable { + values: Rc>, + names: Option>>, + na_value: T, + na_name: Character, iter: Box>>, } -impl<'a, T: Clone> Iterator for RepTypeSubsetIterPairsRef<'a, T> { - type Item = (&'a Character, &'a T); - fn next(&mut self) -> Option { - // None represents NA, will be removed in the future I think. - let maybe_index = self.iter.next()?; +impl RepTypeIntoIterable { + pub fn iter(&mut self) -> RepTypeIterable<'_, T> { + let values = &self.values[..]; - if let Some(index) = maybe_index { - println!("hiii: {}", index); - let value = &self.values[index]; + let names = self.names.as_ref().map(|names| &names[..]); - if let Some(names) = &self.names { - Option::Some((&names[index], value)) - } else { - Option::Some((&Character::NA, value)) - } - } else { - panic!() - // Option::Some((&Character::NA, self.na)) + RepTypeIterable { + values, + names, + na_value: &self.na_value, + na_name: &self.na_name, + iter: &mut self.iter, } } } -impl Iterator for RepTypeSubsetIterPairs { - type Item = (Character, T); +pub struct RepTypeIterable<'a, T: Clone> { + values: &'a [T], + names: Option<&'a [Character]>, + na_value: &'a T, + na_name: &'a Character, + iter: &'a mut Box>>, +} + +impl<'a, T: Clone> Iterator for RepTypeIterable<'a, T> { + type Item = (&'a Character, &'a T); + fn next(&mut self) -> Option { - let maybe_index = self.iter.next()?; - if let Some(index) = maybe_index { - let value = self.values[index].clone(); - // Option::Some((self.names[index].clone(), self.values[index].clone())) - if let Some(names) = &self.names { - Option::Some((names[index].clone(), value)) - } else { - Option::Some((Character::NA, value)) - } + // FIXME: This panics when subsetting with NA + let i = self.iter.next()?.unwrap(); + let value = &self.values[i]; + let name = if let Some(names) = self.names { + &names[i] } else { - Option::Some((Character::NA, T::default())) - } + self.na_name + }; + + Some((name, value)) } } @@ -269,6 +261,24 @@ impl RepType { ) } + pub fn iterable(&self) -> RepTypeIntoIterable { + match self.clone() { + RepType::Subset(values, _, maybe_naming) => { + let iter = Box::new(self.iter_subset_indices().map(|(_, i)| i)); + let values = values.inner_rc(); + let names = maybe_naming.map(|x| x.names.inner_rc()); + + RepTypeIntoIterable { + values, + names, + na_value: T::default(), + na_name: Character::NA, + iter, + } + } + } + } + pub fn ensure_named(&self) { todo!() } @@ -393,22 +403,6 @@ impl RepType { Some(Box::new(iter_names.zip(self.iter_values()))) } - // TODO: this should not be used so much. Instead we should iterate over references. - pub fn iter_pairs<'a>(&'a self) -> Box + 'a> { - match self.clone() { - RepType::Subset(values, _, maybe_naming) => { - let index_iter = self.iter_subset_indices().map(|(_, i)| i); - let names = maybe_naming.map(|x| x.names.inner_rc()); - - Box::new(RepTypeSubsetIterPairs { - values: values.inner_rc(), - names, - iter: Box::new(index_iter), - }) - } - } - } - pub fn iter_subset_indices(&self) -> Box)>> { // TODO: This function is crucial to fix match self.clone() { From 148e2be6e3a13daf27c10c6b32fcb85cb6958866 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 30 Sep 2024 12:51:36 +0530 Subject: [PATCH 19/49] ... --- src/context/core.rs | 25 +++++----- src/object/vector/rep.rs | 14 ++++-- src/object/vector/reptype.rs | 97 +++++++++++++++--------------------- 3 files changed, 62 insertions(+), 74 deletions(-) diff --git a/src/context/core.rs b/src/context/core.rs index 2c611324..5da9ac2e 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -76,14 +76,14 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.pairs().iter()) + Ok(ellipsis.iter_pairs()) } else { - Ok(List::new().pairs().iter()) + Ok(List::new().iter_pairs()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.pairs().iter()) + Ok(more.iter_pairs()) } else { internal_err!() } @@ -92,7 +92,7 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { Ok(c @ Obj::Promise(..)) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); - Ok(List::from(vec![(k, c)]).pairs().iter()) + Ok(List::from(vec![(k, c)]).iter_pairs()) } _ => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); @@ -100,19 +100,18 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { k, Obj::Promise(None, Expr::Symbol(s), self.env()), )]) - .pairs() - .iter()) + .iter_pairs()) } }, (k, c @ Expr::Call(..)) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); let elem = vec![(k, Obj::Promise(None, c, self.env()))]; - Ok(List::from(elem).pairs().iter()) + Ok(List::from(elem).iter_pairs()) } (k, v) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); if let Ok(elem) = self.eval(v) { - Ok(List::from(vec![(k, elem)]).pairs().iter()) + Ok(List::from(vec![(k, elem)]).iter_pairs()) } else { internal_err!() } @@ -131,22 +130,22 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { .map(|pair| match pair { (_, Expr::Ellipsis(None)) => { if let Ok(Obj::List(ellipsis)) = self.get_ellipsis() { - Ok(ellipsis.pairs().iter()) + Ok(ellipsis.iter_pairs()) } else { - Ok(List::from(Vec::<(Character, Obj)>::new()).pairs().iter()) + Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) } } (_, Expr::Ellipsis(Some(name))) => { if let Ok(Obj::List(more)) = self.get(name) { - Ok(more.pairs().iter()) + Ok(more.iter_pairs()) } else { - Ok(List::from(Vec::<(Character, Obj)>::new()).pairs().iter()) + Ok(List::from(Vec::<(Character, Obj)>::new()).iter_pairs()) } } (k, v) => match self.eval_and_finalize(v) { Ok(elem) => { let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); - Ok(List::from(vec![(k, elem)]).pairs().iter()) + Ok(List::from(vec![(k, elem)]).iter_pairs()) } Err(e) => Err(e), }, diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index a1115380..81d48bd5 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -9,6 +9,7 @@ use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::error::Error; +use crate::object::reptype::RepTypeIterPairs; use crate::object::Subsets; use crate::object::{CowObj, Obj, ViewMut}; @@ -76,6 +77,14 @@ impl Rep { } } +impl Rep { + /// Iterate over the names and values of the vector (if the names exist). + pub fn iter_pairs(&self) -> RepTypeIterPairs { + // FIXME: This should maybe return an option + self.0.borrow().clone().iter_pairs() + } +} + impl Rep where T: Clone + Default, @@ -108,11 +117,6 @@ where // self.0.borrow().iter_names() // } - // /// Iterate over the names and values of the vector (if the names exist). - // pub fn iter_pairs(&self) -> Option>> { - // self.0.borrow().iter_named() - // } - fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily let new_repr = { self.borrow().materialize() }; diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index ae12edbd..c59e0d2e 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -234,6 +234,46 @@ impl ViewMut for RepType { } } +impl RepType { + // FIXME: Do we really need iter_named and iter_pairs? + pub fn iter_pairs(&self) -> RepTypeIterPairs { + match self.clone() { + RepType::Subset(values, _, maybe_naming) => { + let iter = Box::new(self.iter_subset_indices().map(|(_, i)| i)); + let values = values.inner_rc(); + let names = maybe_naming.map(|x| x.names.inner_rc()); + + RepTypeIterPairs { + values, + names, + iter, + } + } + } + } +} + +pub struct RepTypeIterPairs { + values: Rc>, + names: Option>>, + iter: Box)>>, +} + +impl Iterator for RepTypeIterPairs { + type Item = (Character, T); + fn next(&mut self) -> Option { + // FIXME: Already assumes no indexing with NA + let i = self.iter.next()?.unwrap(); + let value = self.values[i].clone(); + let name = if let Some(names) = &self.names { + names[i].clone() + } else { + Character::NA + }; + Some((name, value)) + } +} + impl RepType { /// Create an empty vector /// @@ -374,71 +414,16 @@ impl RepType { } } - pub fn iter_values<'a>(&'a self) -> Box + 'a> { - let iter = self.iter_subset_indices(); - match self.clone() { - RepType::Subset(values, ..) => Box::new(iter.map(move |(_, i)| { - let i = i.unwrap(); - let vb = values.borrow(); - (&vb[i]).clone() - })), - } - } - - pub fn iter_names(&self) -> Option>> { - let iter = self.iter_subset_indices(); - match self.clone() { - RepType::Subset(.., None) => None, - RepType::Subset(.., Some(naming)) => Some(Box::new(iter.map(move |(_, i)| { - let i = i.unwrap(); - let vb = naming.names.borrow(); - (&vb[i]).clone() - }))), - } - } - - // FIXME: Do we really need iter_named and iter_pairs? - pub fn iter_named<'a>(&'a self) -> Option + 'a>> { - let iter_names = self.iter_names()?; - Some(Box::new(iter_names.zip(self.iter_values()))) - } - pub fn iter_subset_indices(&self) -> Box)>> { // TODO: This function is crucial to fix match self.clone() { RepType::Subset(vals, subsets, Some(naming)) => { let x = vals.borrow().clone(); - // println!("{}", x.len()); - - // for k in naming.map.borrow().keys() { - // println!("{}", k); - // } - - // for n in naming.names.clone() { - // println!("{}", n); - // } - - // for i in x { - // println("{}", i); - // } - // let iter = subsets.clone().bind_names(naming.map.clone()).into_iter(); - - // for (_, maybe_i) in iter { - // if let Some(i) = maybe_i { - // println!("{}", i); - // } else { - // println!("None"); - // } - // } - // FIXME: we need to call .take() with the proper n Box::new(subsets.bind_names(naming.map).into_iter()) } - RepType::Subset(_, subsets, None) => { - println!("BBB"); - Box::new(subsets.into_iter()) - } + RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), } } From 9662fefcb37ebc12b506c7655fe736c5d8ec0b27 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 30 Sep 2024 12:53:51 +0530 Subject: [PATCH 20/49] ... --- src/object/vector/subsets.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 8b1ca8bf..6007feff 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -78,17 +78,6 @@ impl IntoIterator for NamedSubsets { let mut iter = Box::new((0_usize..).map(|i| (i, Some(i)))) as Self::IntoIter; let Subsets(subsets) = self.subsets; - // Explanation: - // We have a HashMap: String -> Vec - // We start with an Iterator that yields (usize, Option) for 1, ..., n where n is the length - // Each iterator adapts it to (usize, Option) where the first element is the index (1, ..., n_new) and the second the original index - // let's say we do - // l = list(a = 1, b = 2, c = 3) - // l[c(2, 1)][c("b", "a")] which yields list(b = 2, a = 1) - // 1. Iterator gives [(1, Some(2)), (2, Some(1))] - // 2. Iterator: - // 2.1 We find the value for "b". Here we only need to check the names from 1, ..., 2 (the size_hint below) - // 2.2 for subset in subsets { match subset { From 1af22554f9b3a1d8f60967c83ae1139d4b40f214 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 30 Sep 2024 13:39:12 +0530 Subject: [PATCH 21/49] ... --- src/callable/primitive/c.rs | 8 ++++---- src/object/vector/rep.rs | 32 +++----------------------------- src/object/vector/reptype.rs | 27 ++++++++++++++------------- src/object/vector/subset.rs | 2 +- src/object/vector/subsets.rs | 2 +- 5 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index 6318422e..d1a4d063 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -151,7 +151,7 @@ impl Callable for PrimitiveC { .into_iter() .chain(vals.pairs().iter().flat_map( |(_, i)| match i.clone().as_character() { - Ok(Obj::Vector(Vector::Character(v))) => v.into_iter(), + Ok(Obj::Vector(Vector::Character(v))) => v.into_iter_values(), _ => unreachable!(), }, )) @@ -163,7 +163,7 @@ impl Callable for PrimitiveC { .into_iter() .chain(vals.pairs().iter().flat_map( |(_, i)| match i.clone().as_double() { - Ok(Obj::Vector(Vector::Double(v))) => v.into_iter(), + Ok(Obj::Vector(Vector::Double(v))) => v.into_iter_values(), _ => unreachable!(), }, )) @@ -175,7 +175,7 @@ impl Callable for PrimitiveC { .into_iter() .chain(vals.pairs().iter().flat_map( |(_, i)| match i.clone().as_integer() { - Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter(), + Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter_values(), _ => unreachable!(), }, )) @@ -186,7 +186,7 @@ impl Callable for PrimitiveC { .into_iter() .chain(vals.pairs().iter().flat_map( |(_, i)| match i.clone().as_logical() { - Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter(), + Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter_values(), _ => unreachable!(), }, )) diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 81d48bd5..da70c9b3 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -83,6 +83,9 @@ impl Rep { // FIXME: This should maybe return an option self.0.borrow().clone().iter_pairs() } + pub fn into_iter_values(self) -> Box> { + Box::new(self.clone().iter_pairs().map(|(_, x)| x)) + } } impl Rep @@ -297,7 +300,6 @@ where pub fn get_inner(&self, index: usize) -> Option { self.borrow().get_inner(index) } - pub fn get_inner_named(&self, index: usize) -> Option<(Character, T)> { // TODO: I don't think this is really needed. self.borrow().get_inner_named(index) @@ -437,10 +439,6 @@ where .into_inner() .vectorized_partial_cmp(other.0.into_inner()) } - - pub fn iter(&self) -> RepIter { - self.clone().into_iter() - } } impl Default for Rep @@ -452,30 +450,6 @@ where } } -pub struct RepIter(RepTypeIter); - -impl IntoIterator for Rep -where - T: Clone + Default, -{ - type Item = T; - type IntoIter = RepIter; - fn into_iter(self) -> Self::IntoIter { - let x = self.0.into_inner(); - RepIter(x.into_iter()) - } -} - -impl Iterator for RepIter -where - T: Clone + Default, -{ - type Item = T; - fn next(&mut self) -> Option { - self.0.next() - } -} - impl From>> for Rep where T: Clone + Default, diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c59e0d2e..7145940f 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -239,7 +239,7 @@ impl RepType { pub fn iter_pairs(&self) -> RepTypeIterPairs { match self.clone() { RepType::Subset(values, _, maybe_naming) => { - let iter = Box::new(self.iter_subset_indices().map(|(_, i)| i)); + let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); @@ -304,7 +304,7 @@ impl RepType { pub fn iterable(&self) -> RepTypeIntoIterable { match self.clone() { RepType::Subset(values, _, maybe_naming) => { - let iter = Box::new(self.iter_subset_indices().map(|(_, i)| i)); + let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); @@ -414,16 +414,19 @@ impl RepType { } } - pub fn iter_subset_indices(&self) -> Box)>> { + pub fn iter_subset_indices(&self) -> Box>> { // TODO: This function is crucial to fix match self.clone() { - RepType::Subset(vals, subsets, Some(naming)) => { - let x = vals.borrow().clone(); - - // FIXME: we need to call .take() with the proper n - Box::new(subsets.bind_names(naming.map).into_iter()) + RepType::Subset(vals, subsets, maybe_naming) => { + if subsets.is_empty() { + return Box::new((0_usize..vals.len()).map(|x| Some(x))); + } + if let Some(naming) = maybe_naming { + Box::new(subsets.bind_names(naming.map).into_iter().map(|(x, y)| y)) + } else { + Box::new(subsets.into_iter().map(|(_, y)| y)) + } } - RepType::Subset(_, subsets, None) => Box::new(subsets.into_iter()), } } @@ -575,14 +578,12 @@ impl RepType { let l_indices = self.iter_subset_indices(); let r_indices = value.iter_subset_indices(); match (self, value) { - (RepType::Subset(lv, ls, ln), RepType::Subset(rv, rs, _)) => { + (RepType::Subset(lv, ls, ln), RepType::Subset(rv, ..)) => { lv.with_inner_mut(|lvb| { let rvc = rv.clone(); let rvb = rvc.borrow(); - let lv_len = lvb.len(); - - for ((_, li), (_, ri)) in l_indices.zip(r_indices) { + for (li, ri) in l_indices.zip(r_indices) { match (li, ri) { (Some(li), None) => lvb[li] = T::default(), (Some(li), Some(ri)) => lvb[li] = rvb[ri % rvb.len()].clone(), diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index 0fba760b..92f39940 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -239,7 +239,7 @@ impl TryFrom for Subset { value @ Vector::Double(_) => Subset::try_from(value.as_integer()), Vector::Integer(v) => { let y = v - .into_iter() + .into_iter_values() .map(|i| match i { OptionNA::Some(x) => OptionNA::Some(x - 1), OptionNA::NA => OptionNA::NA, diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 6007feff..1f0fba78 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -73,7 +73,7 @@ impl IntoIterator for NamedSubsets { fn into_iter(self) -> Self::IntoIter { let n_subsets = self.subsets.len(); if n_subsets == 0 { - return Box::new((0_usize..n_subsets).map(|(i)| (i, Some(i)))); + return Box::new((0_usize..).map(|i| (i, Some(i)))); } let mut iter = Box::new((0_usize..).map(|i| (i, Some(i)))) as Self::IntoIter; From ac0174a7a3a2e7d2a50c59559c5e3654443e361f Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Mon, 30 Sep 2024 14:48:21 +0530 Subject: [PATCH 22/49] ... --- src/callable/core.rs | 45 +++++++++++++++++------------------- src/object/cow.rs | 2 +- src/object/vector/rep.rs | 27 ++++++++++------------ src/object/vector/reptype.rs | 16 ------------- 4 files changed, 34 insertions(+), 56 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index ada51917..951862cc 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -6,7 +6,9 @@ use crate::cli::Experiment; use crate::context::Context; use crate::error::Error; use crate::object::types::Character; +use crate::object::types::Integer; use crate::object::List; +use crate::object::{CowObj, Subset}; use crate::object::{Expr, ExprList, Obj}; use crate::{internal_err, lang::*}; @@ -46,48 +48,43 @@ pub trait Callable { let mut i: usize = 0; - 'outer: while i < args.len() { - 'inner: { - // check argname with immutable borrow, but drop scope. If - // found, drop borrow so we can mutably assign it - if let (Character::Some(argname), _) = args.get_inner_named(i).unwrap() { - if let Some((Some(_), _)) = formals.remove_named(&argname) { - break 'inner; - } - } - - i += 1; - continue 'outer; - } - - // 1. Remove the name and value from args - // 2. Push them to matched args + let args = args.materialize(); - let (name, obj) = args.remove(i); + let mut indices: Vec = Vec::new(); - matched_args.push_named(name, obj) + for (i, (name, value)) in args.pairs().iter().enumerate() { + if let Character::Some(name) = name { + if let Some((Some(_), _)) = formals.remove_named(&name) { + matched_args.push_named(Character::Some(name.clone()), value.clone()); + continue; + } + } + indices.push((i + 1) as i32); } + let indices: Vec = indices.into_iter().map(|i| Integer::Some(i)).collect(); + let subset = Subset::Indices(indices.into()); + args.subset(subset.into()); + let args = args.materialize(); + // TODO(bug): need to evaluate trailing unassigned params that have // a default value before popping off remaining trailing params // remove any Ellipsis param, and any trailing unassigned params let remainder = formals.pop_trailing(); - for (key, value) in args.pairs().iter() { + for (key, value) in args.iter_pairs() { match key { // named args go directly to ellipsis, they did not match a formal - Character::Some(arg) => { - ellipsis.push_named(Character::Some(arg.clone()), value.clone()) - } + Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value), // unnamed args populate next formal, or ellipsis if formals exhausted Character::NA => { let next_unassigned_formal = formals.remove(0); if let Some((Some(param), _)) = next_unassigned_formal { - matched_args.push_named(Character::Some(param), value.clone()); + matched_args.push_named(Character::Some(param), value); } else { - ellipsis.push_named(Character::NA, value.clone()); + ellipsis.push_named(Character::NA, value); } } } diff --git a/src/object/cow.rs b/src/object/cow.rs index f8222c66..45392dec 100644 --- a/src/object/cow.rs +++ b/src/object/cow.rs @@ -11,7 +11,7 @@ pub trait ViewMut { /// Internal Data representation for copy-on-write semantics. #[derive(Debug, PartialEq, Default)] -pub struct CowObj(Rc>>); +pub struct CowObj(pub Rc>>); impl Clone for CowObj { fn clone(&self) -> Self { diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index da70c9b3..a92c261f 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -297,14 +297,6 @@ where x.map(|x| x.into()) } - pub fn get_inner(&self, index: usize) -> Option { - self.borrow().get_inner(index) - } - pub fn get_inner_named(&self, index: usize) -> Option<(Character, T)> { - // TODO: I don't think this is really needed. - self.borrow().get_inner_named(index) - } - pub fn values(&self) -> CowObj> { self.materialize_inplace(); match self.0.borrow().clone() { @@ -468,19 +460,24 @@ where } } +// TODO: I think this should err when rep has length > 1 impl TryInto for Rep> where OptionNA: AtomicMode + Clone + CoercibleInto>, + T: 'static, { type Error = (); fn try_into(self) -> Result { - self.get_inner(0).map_or( - Err(()), - |i| match CoercibleInto::>::coerce_into(i) { - OptionNA::Some(x) => Ok(x), - OptionNA::NA => Err(()), - }, - ) + self.iter_pairs() + .next() + .map(|(_, x)| x) + .map_or( + Err(()), + |i| match CoercibleInto::>::coerce_into(i) { + OptionNA::Some(x) => Ok(x), + OptionNA::NA => Err(()), + }, + ) } } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 7145940f..268e6809 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -756,22 +756,6 @@ impl RepType { } } } - pub fn get_inner_named(&self, index: usize) -> Option<(OptionNA, T)> { - // TODO: I don't think this is really needed - match &self { - RepType::Subset(.., maybe_naming) => { - let x = self.get_inner(index)?; - if let Some(naming) = maybe_naming { - Some(( - OptionNA::Some(naming.names.borrow().get(index).unwrap().to_string()), - x, - )) - } else { - Some((OptionNA::NA, x)) - } - } - } - } } impl TryInto for RepType> From dbbd5417bc866757dfb8cd429b57f9383c2dddd1 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 09:12:43 +0530 Subject: [PATCH 23/49] ... --- src/object/vector/rep.rs | 29 +------------------- src/object/vector/reptype.rs | 52 +++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index a92c261f..55a57f11 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -42,34 +42,7 @@ impl Rep { /// Get the inner value mutably. /// This is used for assignments like `list(1)[[1]] = 10`. pub fn try_get_inner_mut(&self, subset: Subset) -> Result { - match self.borrow().clone() { - RepType::Subset(values, mut subsets, maybe_naming) => { - subsets.push(subset); - if let Some(naming) = maybe_naming { - let mut iter = subsets.bind_names(naming.map).into_iter(); - - // Here, the subset must produce exactly one index, i.e. we call next() twice and the second - // yielded element must be None - if let Some((i, _)) = iter.next() { - if let None = iter.next() { - values.with_inner_mut(|v| { - v.get_mut(i) - .map_or(Err(Error::Other("todo".to_string())), |x| { - Ok(x.view_mut()) - }) - }) - } else { - Err(Error::Other("todo".to_string())) - } - } else { - Err(Error::Other("todo".to_string())) - } - } else { - // TODO - Err(Error::Other("todo".to_string())) - } - } - } + self.borrow().try_get_inner_mut(subset).into() } pub fn try_get_inner(&self, subset: Subset) -> Result { diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 268e6809..fdaaa5e9 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -6,6 +6,7 @@ use super::subset::Subset; use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; +use crate::error::Error; use crate::object::{CowObj, Obj, ViewMut}; use hashbrown::HashMap; use std::cell::RefCell; @@ -127,12 +128,47 @@ impl Default for RepType { impl RepType { /// Retrieve the internal data as a mutable view. - pub fn try_get_inner_mut(&self, index: usize) -> Option { - match self { - RepType::Subset(v, subsets, _) => { - let vb = v.borrow(); - let index = subsets.get_index_at(index).unwrap(); - vb.get(index).map(|i| i.view_mut()) + pub fn try_get_inner_mut(&self, subset: Subset) -> Result { + let self_subset = self.subset(subset); + match self_subset { + RepType::Subset(..) => { + let mut iter = self.iter_subset_indices(); + + if let Some(i) = iter.next() { + iter.next() + .ok_or(Error::Other("subset is not of length 1".to_string()))?; + + // TODO: subsetting with NA should not be possible. + let i = i.unwrap(); + + Ok(self.with_inner_mut(|values| values[i].view_mut())) + } else { + return Err(Error::Other("subset is empty".to_string())); + } + + // if let Some(naming) = maybe_naming { + // let mut iter = subsets.bind_names(naming.map).into_iter(); + + // // Here, the subset must produce exactly one index, i.e. we call next() twice and the second + // // yielded element must be None + // if let Some((i, _)) = iter.next() { + // if let None = iter.next() { + // values.with_inner_mut(|v| { + // v.get_mut(i) + // .map_or(Err(Error::Other("todo".to_string())), |x| { + // Ok(x.view_mut()) + // }) + // }) + // } else { + // Err(Error::Other("todo".to_string())) + // } + // } else { + // Err(Error::Other("todo".to_string())) + // } + // } else { + // // TODO + // Err(Error::Other("todo".to_string())) + // } } } } @@ -305,6 +341,10 @@ impl RepType { match self.clone() { RepType::Subset(values, _, maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); + let iter2 = Box::new(self.iter_subset_indices()); + for i in iter2 { + println!("{}", i.unwrap()); + } let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); From 489107f5ec6451a672e81b34a66d3a1fda07fdb6 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 13:45:52 +0530 Subject: [PATCH 24/49] ... --- src/callable/core.rs | 32 +++++++++++---- src/callable/operators.rs | 17 ++++++-- src/callable/primitive/paste.rs | 12 ++++++ src/lang.rs | 11 +++++ src/object/vector/core.rs | 11 +++++ src/object/vector/rep.rs | 5 +++ src/object/vector/reptype.rs | 46 +++++++++++++++++---- src/object/vector/subset.rs | 53 ++++++++++++++++++------ src/object/vector/subsets.rs | 73 ++++++++++++++++++++++++++++++--- 9 files changed, 221 insertions(+), 39 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 951862cc..9dabafa5 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -8,7 +8,7 @@ use crate::error::Error; use crate::object::types::Character; use crate::object::types::Integer; use crate::object::List; -use crate::object::{CowObj, Subset}; +use crate::object::Subset; use crate::object::{Expr, ExprList, Obj}; use crate::{internal_err, lang::*}; @@ -46,26 +46,42 @@ pub trait Callable { // assign named args to corresponding formals - let mut i: usize = 0; - let args = args.materialize(); let mut indices: Vec = Vec::new(); - for (i, (name, value)) in args.pairs().iter().enumerate() { - if let Character::Some(name) = name { + for (i, (maybe_name, value)) in args.pairs().iter().enumerate() { + if let Character::Some(name) = maybe_name { if let Some((Some(_), _)) = formals.remove_named(&name) { matched_args.push_named(Character::Some(name.clone()), value.clone()); continue; } } - indices.push((i + 1) as i32); + println!("push it {}", i); + indices.push(i as i32); + } + + println!("matched_args start"); + for (key, _) in matched_args.pairs().iter() { + dbg!(key); } + println!("matched_args end"); let indices: Vec = indices.into_iter().map(|i| Integer::Some(i)).collect(); + dbg!(&indices); let subset = Subset::Indices(indices.into()); - args.subset(subset.into()); - let args = args.materialize(); + let args = args.subset(subset.into()).materialize(); + + // println!("matching args start"); + // for (maybe_name, _) in args.pairs().iter() { + // dbg!(&maybe_name); + // } + // println!("matching args end"); + println!("args start"); + for (maybe_name, _) in args.pairs().iter() { + dbg!(&maybe_name); + } + println!("args end"); // TODO(bug): need to evaluate trailing unassigned params that have // a default value before popping off remaining trailing params diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 7ad94de0..a1637b74 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -3,6 +3,7 @@ use r_derive::*; use super::core::*; use crate::context::Context; use crate::error::Error; +use crate::lang::Signal; use crate::lang::{CallStack, EvalResult}; use crate::object::types::*; use crate::object::*; @@ -409,7 +410,10 @@ impl Callable for PostfixIndex { let x = args.unnamed_binary_args(); let what = stack.eval_mut(x.0)?; let index = stack.eval(x.1)?; - what.try_get_inner_mut(index) + // TODO: Ensure that index is of length 1. + // We cannot call into try_get_inner_mut because not all objects can be modified in-place + // Instead, we internally simply return the slice which can be modified in-place + what.try_get(index) } fn call_assign(&self, value: Expr, args: ExprList, stack: &mut CallStack) -> EvalResult { @@ -424,10 +428,15 @@ impl Callable for PostfixIndex { }; let value = stack.eval(value)?; - let index = stack.eval(index)?; - let what = stack.eval_mut(what)?.try_get_inner_mut(index)?; + let mut what = stack.eval_mut(what)?; + let index = stack.eval_mut(index)?; + + let subset = index.try_into()?; - what.replace(value) + match what.clone() { + Obj::List(mut r) => r.set_subset(subset, what).map_err(|e| Signal::Error(e)), + _ => unimplemented!(), + } } } diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index c9dc7e6b..a68dd1ef 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -58,6 +58,13 @@ impl Callable for PrimitivePaste { let (args, ellipsis) = self.match_arg_exprs(args, stack)?; let ellipsis = force_promises(ellipsis, stack)?; + + println!("ellipsis start"); + for x in &ellipsis { + dbg!(&x.1); + } + println!("ellipsis end"); + let args = force_promises(args, stack)?; let mut sep = String::from(" "); @@ -94,6 +101,9 @@ impl Callable for PrimitivePaste { } } + dbg!(&collapse); + dbg!(&sep); + // coerce all of our remaining arguments into vectors of strings let vec_s_vec: Vec> = ellipsis .into_iter() @@ -125,6 +135,8 @@ impl Callable for PrimitivePaste { }); }); + dbg!(&output); + if should_collapse { output = vec![output.join(&collapse)]; } diff --git a/src/lang.rs b/src/lang.rs index f20135d7..4924b460 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -254,6 +254,17 @@ impl Obj { } } + pub fn set_subset(&mut self, subset: Subset, value: Obj) -> EvalResult { + match self { + Obj::Vector(v) { + v.set_sub + } + } + todo!() + m + } + + // use set_subset instead pub fn set_named(&mut self, name: &str, value: Obj) -> EvalResult { todo!() // I feel this is implemented twice diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index c03961fa..811460f3 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -87,6 +87,17 @@ impl Vector { } } + pub fn set_subset(&mut self, subset: Subset, value: ) -> Result { + use Vector::*; + match self { + Double(x) => x.subset(Double), + Integer(x) => x.get(index).map(Integer), + Logical(x) => x.get(index).map(Logical), + Character(x) => x.get(index).map(Character), + } + + } + /// Iterate over the names of the vector. pub fn iter_names(&self) -> Option>>> { todo!() diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 55a57f11..c6d0ba13 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -277,6 +277,10 @@ where } } + pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { + self.0.borrow_mut().set_subset(subset, value) + } + pub fn push_named(&self, name: OptionNA, value: T) { self.borrow().push_named(name, value) } @@ -534,6 +538,7 @@ where return write!(f, "character(0)"); } } + // FIXME: This should use the new rep API let nlen = format!("{}", n).len(); // TODO: iteratively calculate when we hit max print so our diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index fdaaa5e9..4b18565e 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -135,8 +135,8 @@ impl RepType { let mut iter = self.iter_subset_indices(); if let Some(i) = iter.next() { - iter.next() - .ok_or(Error::Other("subset is not of length 1".to_string()))?; + // iter.next() + // .ok_or(Error::Other("subset is not of length 1".to_string()))?; // TODO: subsetting with NA should not be possible. let i = i.unwrap(); @@ -337,14 +337,36 @@ impl RepType { ) } + pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { + match &self { + RepType::Subset(..) => { + let err = Error::Other("subset must have length 1".to_string()); + + let mut iter = self.clone().subset(subset).iter_subset_indices(); + let i1 = iter.next(); + + // check that subset has exactly length 1 + // assumes no indexing with NA (unwrap the option) + let i = if let Some(i) = i1 { + if let Some(_) = iter.next() { + return Err(err); + } + i + } else { + return Err(err); + } + .unwrap(); + + self.with_inner_mut(|v| v[i] = value.clone()); + Ok(value.clone()) + } + } + } + pub fn iterable(&self) -> RepTypeIntoIterable { match self.clone() { RepType::Subset(values, _, maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); - let iter2 = Box::new(self.iter_subset_indices()); - for i in iter2 { - println!("{}", i.unwrap()); - } let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); @@ -455,16 +477,24 @@ impl RepType { } pub fn iter_subset_indices(&self) -> Box>> { + // TODO: Why do we have to do -1 here. Shouldnt' .filter() and the Iterator method of NamedSubsets + // not already return the 0-based indices? // TODO: This function is crucial to fix match self.clone() { RepType::Subset(vals, subsets, maybe_naming) => { if subsets.is_empty() { return Box::new((0_usize..vals.len()).map(|x| Some(x))); } + if let Some(naming) = maybe_naming { - Box::new(subsets.bind_names(naming.map).into_iter().map(|(x, y)| y)) + Box::new( + subsets + .bind_names(naming.map) + .into_iter() + .map(|(x, y)| y.map(|y| y)), + ) } else { - Box::new(subsets.into_iter().map(|(_, y)| y)) + Box::new(subsets.into_iter().map(|(_, y)| y.map(|y| y))) } } } diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index 92f39940..0b10631b 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::ops::Range; +use std::ops::{DerefMut, Range}; use std::rc::Rc; use super::{types::*, OptionNA, Vector}; @@ -14,6 +14,8 @@ use crate::object::{CowObj, Obj}; /// #[derive(Debug, Clone, PartialEq)] pub enum Subset { + // This is currently 0-index. + // TODO: I think this should be 1-indexed as pushing integer vectors as a subset otherwise requires an allocation. Indices(CowObj>), Mask(CowObj>), Names(CowObj>), @@ -192,18 +194,43 @@ impl TryFrom for Subset { fn try_from(value: Obj) -> Result { let err = Error::Other("Cannot use object for indexing".to_string()); match value { - Obj::Vector(v) => match v { - Vector::Double(_) => { - if let Vector::Integer(x) = v.as_integer() { - Ok(Subset::Indices(x.values())) - } else { - unreachable!() - } - } - Vector::Integer(x) => Ok(Subset::Indices(x.values())), - Vector::Character(x) => Ok(Subset::Names(x.values())), - Vector::Logical(x) => Ok(Subset::Mask(x.values())), - }, + Obj::Vector(v) => Subset::try_from(v), + // Obj::Vector(v) => match v { + // Vector::Double(_) => { + // if let Vector::Integer(x) = v.as_integer() { + // let x = Obj::Vector(x.into()); + // Subset::try_from(x) + // // todo!() + // // v.try_from() + // // // FIXME: This needs to -1 + // // let indices: Vec = x + // // .values() + // // .inner_rc() + // // .into_iter() + // // .map(|i| i.map(|i| OptionNA::Some(i - 1))) + // // .collect(); + + // // todo!() + // // // Ok(Subset::Indices(indices.into())) + // } else { + // unreachable!() + // } + // } + // Vector::Integer(x) => { + // let indices: Vec = x + // .pairs() + // .iter() + // .map(|(_, x)| x.clone().map(|i| i - 1)) + // .collect(); + // Subset::Indices(x.values()) + + // todo!() + + // // Ok(Subset::Indices(x.values())), + // } + // Vector::Character(x) => Ok(Subset::Names(x.values())), + // Vector::Logical(x) => Ok(Subset::Mask(x.values())), + // }, _ => err.into(), } } diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 1f0fba78..fbd2d0d1 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -71,14 +71,8 @@ impl IntoIterator for NamedSubsets { type IntoIter = Box>; fn into_iter(self) -> Self::IntoIter { - let n_subsets = self.subsets.len(); - if n_subsets == 0 { - return Box::new((0_usize..).map(|i| (i, Some(i)))); - } - let mut iter = Box::new((0_usize..).map(|i| (i, Some(i)))) as Self::IntoIter; let Subsets(subsets) = self.subsets; - for subset in subsets { match subset { Subset::Names(names) => { @@ -156,6 +150,8 @@ impl IntoIterator for Subsets { #[cfg(test)] mod test { + use std::borrow::BorrowMut; + use crate::object::Vector; #[test] @@ -250,4 +246,69 @@ mod test { let expect = Vector::from(vec![1, 2, 3, 4, 102, 101, 7, 8, 9, 10]); assert_eq!(x, expect) } + + #[test] + fn iter_named_subsets() { + use crate::object::reptype::Naming; + use crate::object::reptype::RepType; + use crate::object::types::{Character, Integer, Logical}; + use crate::object::CowObj; + use crate::object::{Subset, Subsets}; + use hashbrown::HashMap; + use std::cell::RefCell; + use std::rc::Rc; + + let v = CowObj::new(Rc::new(RefCell::new(Rc::new( + vec![1, 2, 3] + .into_iter() + .map(|i| Integer::Some(i)) + .collect(), + )))); + let n = CowObj::new(Rc::new(RefCell::new(Rc::new( + vec!["a".to_string(), "b".to_string(), "c".to_string()] + .into_iter() + .map(|i| Character::Some(i)) + .collect(), + )))); + let s_names: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( + vec!["a".to_string()] + .into_iter() + .map(|i| Character::Some(i)) + .collect(), + )))); + let s_indices: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( + vec![1, 2].into_iter().map(|i| Integer::Some(i)).collect(), + )))); + let s_logical: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( + vec![true, true, true] + .into_iter() + .map(|i| Logical::Some(i)) + .collect(), + )))); + let mut m1: HashMap> = HashMap::new(); + m1.insert("a".to_string(), vec![0 as usize]); + m1.insert("b".to_string(), vec![1 as usize]); + m1.insert("c".to_string(), vec![2 as usize]); + let m: CowObj>> = + CowObj::new(Rc::new(RefCell::new(Rc::new(m1)))); + let naming = Naming { map: m, names: n }; + let x = RepType::Subset(v, Subsets(vec![Subset::Indices(s_indices)]), Option::None); + for i in x.iter_subset_indices().take(3) { + println!("{}", i.unwrap()); + } + // let x: CowObj::from(vec![1, 2, 3]); + // // let x = RepType::Sub + } + + // table: + // -- has_names: true + // - range: currently unused + // - mask: correct + // - names: correct + // - indices: false + // -- has_names: false + // - range: currently unused + // - mask: correct + // - names: unimplemented + // - indices: false } From cc3a77d92ce97b92c013939bc38534e4df915831 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 13:46:50 +0530 Subject: [PATCH 25/49] ... --- src/lang.rs | 6 ------ src/object/vector/core.rs | 18 +++++++++--------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/lang.rs b/src/lang.rs index 4924b460..17950818 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -255,13 +255,7 @@ impl Obj { } pub fn set_subset(&mut self, subset: Subset, value: Obj) -> EvalResult { - match self { - Obj::Vector(v) { - v.set_sub - } - } todo!() - m } // use set_subset instead diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 811460f3..883cad6d 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -87,15 +87,15 @@ impl Vector { } } - pub fn set_subset(&mut self, subset: Subset, value: ) -> Result { - use Vector::*; - match self { - Double(x) => x.subset(Double), - Integer(x) => x.get(index).map(Integer), - Logical(x) => x.get(index).map(Logical), - Character(x) => x.get(index).map(Character), - } - + pub fn set_subset(&mut self, subset: Subset, value: Obj) -> Result { + todo!() + // use Vector::*; + // match self { + // Double(x) => x.subset(Double), + // Integer(x) => x.get(index).map(Integer), + // Logical(x) => x.get(index).map(Logical), + // Character(x) => x.get(index).map(Character), + // } } /// Iterate over the names of the vector. From a93953ab31560101c26702c79584bd33399b0fd5 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 13:55:15 +0530 Subject: [PATCH 26/49] ... --- src/callable/core.rs | 6 ++--- src/callable/operators.rs | 11 ++++---- src/callable/primitive/c.rs | 4 +-- src/callable/primitive/paste.rs | 2 +- src/context/core.rs | 10 ++++---- src/lang.rs | 3 +-- src/object/list.rs | 4 --- src/object/vector/rep.rs | 12 +++------ src/object/vector/reptype.rs | 45 +++++++++++++++------------------ src/object/vector/subset.rs | 2 +- src/object/vector/subsets.rs | 18 ++++++------- 11 files changed, 52 insertions(+), 65 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 9dabafa5..feea9f03 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -52,7 +52,7 @@ pub trait Callable { for (i, (maybe_name, value)) in args.pairs().iter().enumerate() { if let Character::Some(name) = maybe_name { - if let Some((Some(_), _)) = formals.remove_named(&name) { + if let Some((Some(_), _)) = formals.remove_named(name) { matched_args.push_named(Character::Some(name.clone()), value.clone()); continue; } @@ -67,10 +67,10 @@ pub trait Callable { } println!("matched_args end"); - let indices: Vec = indices.into_iter().map(|i| Integer::Some(i)).collect(); + let indices: Vec = indices.into_iter().map(Integer::Some).collect(); dbg!(&indices); let subset = Subset::Indices(indices.into()); - let args = args.subset(subset.into()).materialize(); + let args = args.subset(subset).materialize(); // println!("matching args start"); // for (maybe_name, _) in args.pairs().iter() { diff --git a/src/callable/operators.rs b/src/callable/operators.rs index a1637b74..c45b549b 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -428,15 +428,16 @@ impl Callable for PostfixIndex { }; let value = stack.eval(value)?; - let mut what = stack.eval_mut(what)?; - let index = stack.eval_mut(index)?; + let what = stack.eval_mut(what)?; + let index = stack.eval(index)?; let subset = index.try_into()?; - match what.clone() { - Obj::List(mut r) => r.set_subset(subset, what).map_err(|e| Signal::Error(e)), + Ok(match what { + Obj::List(mut v) => v.set_subset(subset, value)?, + Obj::Vector(mut v) => v.set_subset(subset, value).map(|v| Obj::Vector(v))?, _ => unimplemented!(), - } + }) } } diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index d1a4d063..ae3bc425 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -90,9 +90,7 @@ impl Callable for PrimitiveC { let nms = pairs.iter().flat_map(|(name, obj)| { let maybe_prefix = name .clone() - .as_option() - .as_ref() - .and_then(|n| Option::Some(n.clone())); + .as_option().clone(); if let Obj::Vector(v) = obj { let maybe_names_iter = v.iter_names(); diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index a68dd1ef..3f51e746 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -148,7 +148,7 @@ impl Callable for PrimitivePaste { #[cfg(test)] mod test { use super::*; - use crate::object::types::*; + use crate::r; #[test] diff --git a/src/context/core.rs b/src/context/core.rs index 5da9ac2e..954d0ddf 100644 --- a/src/context/core.rs +++ b/src/context/core.rs @@ -91,11 +91,11 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { // Avoid creating a new closure just to point to another, just reuse it (k, Expr::Symbol(s)) => match self.env().get(s.clone()) { Ok(c @ Obj::Promise(..)) => { - let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + let k = k.map_or(OptionNA::NA, OptionNA::Some); Ok(List::from(vec![(k, c)]).iter_pairs()) } _ => { - let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + let k = k.map_or(OptionNA::NA, OptionNA::Some); Ok(List::from(vec![( k, Obj::Promise(None, Expr::Symbol(s), self.env()), @@ -104,12 +104,12 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { } }, (k, c @ Expr::Call(..)) => { - let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + let k = k.map_or(OptionNA::NA, OptionNA::Some); let elem = vec![(k, Obj::Promise(None, c, self.env()))]; Ok(List::from(elem).iter_pairs()) } (k, v) => { - let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + let k = k.map_or(OptionNA::NA, OptionNA::Some); if let Ok(elem) = self.eval(v) { Ok(List::from(vec![(k, elem)]).iter_pairs()) } else { @@ -144,7 +144,7 @@ pub trait Context: std::fmt::Debug + std::fmt::Display { } (k, v) => match self.eval_and_finalize(v) { Ok(elem) => { - let k = k.map_or(OptionNA::NA, |x| OptionNA::Some(x)); + let k = k.map_or(OptionNA::NA, OptionNA::Some); Ok(List::from(vec![(k, elem)]).iter_pairs()) } Err(e) => Err(e), diff --git a/src/lang.rs b/src/lang.rs index 17950818..5be05430 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -3,7 +3,6 @@ use crate::cli::Experiment; use crate::context::Context; use crate::error::*; use crate::internal_err; -use crate::object::rep::Rep; use crate::object::types::*; use crate::object::List; use crate::object::*; @@ -419,7 +418,7 @@ fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt match value { Obj::List(nested_values) => { writeln!(f, "{}", breadcrumbs)?; - display_list(&nested_values, f, Some(breadcrumbs))? + display_list(nested_values, f, Some(breadcrumbs))? } _ => write!(f, "{}\n{}\n", breadcrumbs, value)?, } diff --git a/src/object/list.rs b/src/object/list.rs index a8d26fa1..e7c682fa 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,9 +1,5 @@ -use hashbrown::HashMap; -use crate::error::Error; -use crate::lang::EvalResult; use crate::object::rep::Rep; -use crate::object::vector::types::Character; use super::*; diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index c6d0ba13..16d4709d 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -4,7 +4,7 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; use super::reptype::{Naming, RepType}; -use super::reptype::{RepTypeIntoIterable, RepTypeIter}; +use super::reptype::RepTypeIntoIterable; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; @@ -42,11 +42,11 @@ impl Rep { /// Get the inner value mutably. /// This is used for assignments like `list(1)[[1]] = 10`. pub fn try_get_inner_mut(&self, subset: Subset) -> Result { - self.borrow().try_get_inner_mut(subset).into() + self.borrow().try_get_inner_mut(subset) } pub fn try_get_inner(&self, subset: Subset) -> Result { - self.try_get_inner_mut(subset).map(|v| v.clone()) + self.try_get_inner_mut(subset) } } @@ -127,11 +127,7 @@ where match self.borrow().clone() { RepType::Subset(_, s, n) => { if s.is_empty() { - if let Option::Some(n) = n { - Option::Some(n.clone().names) - } else { - Option::None - } + n.map(|n| n.clone().names) } else { unimplemented!() } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 4b18565e..5fe5aa08 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -7,7 +7,7 @@ use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::error::Error; -use crate::object::{CowObj, Obj, ViewMut}; +use crate::object::{CowObj, ViewMut}; use hashbrown::HashMap; use std::cell::RefCell; use std::rc::Rc; @@ -143,7 +143,7 @@ impl RepType { Ok(self.with_inner_mut(|values| values[i].view_mut())) } else { - return Err(Error::Other("subset is empty".to_string())); + Err(Error::Other("subset is empty".to_string())) } // if let Some(naming) = maybe_naming { @@ -292,7 +292,7 @@ impl RepType { pub struct RepTypeIterPairs { values: Rc>, names: Option>>, - iter: Box)>>, + iter: Box>>, } impl Iterator for RepTypeIterPairs { @@ -348,7 +348,7 @@ impl RepType { // check that subset has exactly length 1 // assumes no indexing with NA (unwrap the option) let i = if let Some(i) = i1 { - if let Some(_) = iter.next() { + if iter.next().is_some() { return Err(err); } i @@ -446,7 +446,7 @@ impl RepType { pub fn remove(&self, index: usize) -> (Character, T) { match self { RepType::Subset(values, Subsets(subsets), maybe_naming) => { - if let [] = subsets.as_slice() { + if subsets.as_slice().is_empty() { let value = values.with_inner_mut(|values| values.remove(index)); let name = if let Some(naming) = maybe_naming { @@ -454,7 +454,7 @@ impl RepType { } else { OptionNA::NA }; - return (name, value); + (name, value) } else { unimplemented!() } @@ -483,7 +483,7 @@ impl RepType { match self.clone() { RepType::Subset(vals, subsets, maybe_naming) => { if subsets.is_empty() { - return Box::new((0_usize..vals.len()).map(|x| Some(x))); + return Box::new((0_usize..vals.len()).map(Some)); } if let Some(naming) = maybe_naming { @@ -491,10 +491,10 @@ impl RepType { subsets .bind_names(naming.map) .into_iter() - .map(|(x, y)| y.map(|y| y)), + .map(|(x, y)| y), ) } else { - Box::new(subsets.into_iter().map(|(_, y)| y.map(|y| y))) + Box::new(subsets.into_iter().map(|(_, y)| y)) } } } @@ -502,21 +502,18 @@ impl RepType { /// Reindex the mapping from names to indices. pub fn reindex(&mut self) { - match self { - RepType::Subset(.., Some(naming)) => naming.map.with_inner_mut(|map| { - map.drain(); - - for (i, maybe_name) in naming.names.borrow().iter().enumerate() { - if let OptionNA::Some(name) = maybe_name { - let indices = map.entry(name.clone()).or_default(); - if !indices.contains(&i) { - indices.push(i) - } + if let RepType::Subset(.., Some(naming)) = self { naming.map.with_inner_mut(|map| { + map.drain(); + + for (i, maybe_name) in naming.names.borrow().iter().enumerate() { + if let OptionNA::Some(name) = maybe_name { + let indices = map.entry(name.clone()).or_default(); + if !indices.contains(&i) { + indices.push(i) } } - }), - _ => (), - } + } + }) } } pub fn dedup_last(self) -> Self { @@ -548,7 +545,7 @@ impl RepType { }); RepType::Subset(values, subsets, Some(naming)) } - RepType::Subset(.., None) => return self, + RepType::Subset(.., None) => self, } } @@ -865,7 +862,7 @@ impl From, T)>> for RepType { let mut names = Vec::with_capacity(value.len()); let mut values = Vec::with_capacity(value.len()); for (k, v) in value.into_iter() { - names.push(k.map_or(Character::NA, |x| Character::Some(x))); + names.push(k.map_or(Character::NA, Character::Some)); values.push(v) } let naming = Naming::from(names); diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index 0b10631b..a5a2558b 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::ops::{DerefMut, Range}; +use std::ops::Range; use std::rc::Rc; use super::{types::*, OptionNA, Vector}; diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index fbd2d0d1..a04c359b 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -150,7 +150,7 @@ impl IntoIterator for Subsets { #[cfg(test)] mod test { - use std::borrow::BorrowMut; + use crate::object::Vector; @@ -261,34 +261,34 @@ mod test { let v = CowObj::new(Rc::new(RefCell::new(Rc::new( vec![1, 2, 3] .into_iter() - .map(|i| Integer::Some(i)) + .map(Integer::Some) .collect(), )))); let n = CowObj::new(Rc::new(RefCell::new(Rc::new( vec!["a".to_string(), "b".to_string(), "c".to_string()] .into_iter() - .map(|i| Character::Some(i)) + .map(Character::Some) .collect(), )))); let s_names: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( vec!["a".to_string()] .into_iter() - .map(|i| Character::Some(i)) + .map(Character::Some) .collect(), )))); let s_indices: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec![1, 2].into_iter().map(|i| Integer::Some(i)).collect(), + vec![1, 2].into_iter().map(Integer::Some).collect(), )))); let s_logical: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( vec![true, true, true] .into_iter() - .map(|i| Logical::Some(i)) + .map(Logical::Some) .collect(), )))); let mut m1: HashMap> = HashMap::new(); - m1.insert("a".to_string(), vec![0 as usize]); - m1.insert("b".to_string(), vec![1 as usize]); - m1.insert("c".to_string(), vec![2 as usize]); + m1.insert("a".to_string(), vec![0_usize]); + m1.insert("b".to_string(), vec![1_usize]); + m1.insert("c".to_string(), vec![2_usize]); let m: CowObj>> = CowObj::new(Rc::new(RefCell::new(Rc::new(m1)))); let naming = Naming { map: m, names: n }; From 4c714f7bc6af5dc0dd1bdbd012c495909a50912a Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 13:56:17 +0530 Subject: [PATCH 27/49] ... --- src/callable/operators.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/callable/operators.rs b/src/callable/operators.rs index c45b549b..d47efcde 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -3,7 +3,6 @@ use r_derive::*; use super::core::*; use crate::context::Context; use crate::error::Error; -use crate::lang::Signal; use crate::lang::{CallStack, EvalResult}; use crate::object::types::*; use crate::object::*; @@ -435,7 +434,7 @@ impl Callable for PostfixIndex { Ok(match what { Obj::List(mut v) => v.set_subset(subset, value)?, - Obj::Vector(mut v) => v.set_subset(subset, value).map(|v| Obj::Vector(v))?, + Obj::Vector(mut v) => v.set_subset(subset, value).map(Obj::Vector)?, _ => unimplemented!(), }) } From fec9c467832f05e54f6fb3c24ffb59a1e270cb97 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Tue, 1 Oct 2024 15:21:28 +0530 Subject: [PATCH 28/49] ... --- src/callable/operators.rs | 2 +- src/callable/primitive/c.rs | 4 +- src/callable/primitive/paste.rs | 2 +- src/lang.rs | 2 +- src/object/list.rs | 9 +++- src/object/vector/core.rs | 56 ++++++++++++++++------- src/object/vector/rep.rs | 2 +- src/object/vector/reptype.rs | 35 +++++++-------- src/object/vector/subsets.rs | 6 +-- src/object/vector/types.rs | 79 +++++++++++++++++++++++++++++++++ 10 files changed, 147 insertions(+), 50 deletions(-) diff --git a/src/callable/operators.rs b/src/callable/operators.rs index d47efcde..1796ff31 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -412,7 +412,7 @@ impl Callable for PostfixIndex { // TODO: Ensure that index is of length 1. // We cannot call into try_get_inner_mut because not all objects can be modified in-place // Instead, we internally simply return the slice which can be modified in-place - what.try_get(index) + what.try_get_inner_mut(index) } fn call_assign(&self, value: Expr, args: ExprList, stack: &mut CallStack) -> EvalResult { diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index ae3bc425..c0b194e1 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -88,9 +88,7 @@ impl Callable for PrimitiveC { let names: Option> = if named { let mut pairs = vals.pairs(); let nms = pairs.iter().flat_map(|(name, obj)| { - let maybe_prefix = name - .clone() - .as_option().clone(); + let maybe_prefix = name.clone().as_option().clone(); if let Obj::Vector(v) = obj { let maybe_names_iter = v.iter_names(); diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index 3f51e746..b8699c13 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -148,7 +148,7 @@ impl Callable for PrimitivePaste { #[cfg(test)] mod test { use super::*; - + use crate::r; #[test] diff --git a/src/lang.rs b/src/lang.rs index 5be05430..22371b9c 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -318,7 +318,7 @@ impl Obj { // Used for [[ ]] syntax pub fn try_get_inner(&self, index: Obj) -> EvalResult { match self { - Obj::Vector(v) => v.try_get_inner(index), + Obj::Vector(v) => v.try_get(index), Obj::List(l) => EvalResult::Ok(l.try_get_inner(index.try_into()?)?), obj => obj.as_list()?.try_get_inner(index), } diff --git a/src/object/list.rs b/src/object/list.rs index e7c682fa..e0311a9c 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,4 +1,3 @@ - use crate::object::rep::Rep; use super::*; @@ -360,4 +359,12 @@ mod tests { l[[1]] == 10 & l[[2]] == 20 "#}} } + #[test] + fn list_assign() { + r_expect! {{r#" + l = (function() null, ) + l[[1]] = 1 + l[[1]] == 1 + "#}} + } } diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 883cad6d..fd7e4d5c 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -88,14 +88,21 @@ impl Vector { } pub fn set_subset(&mut self, subset: Subset, value: Obj) -> Result { - todo!() - // use Vector::*; - // match self { - // Double(x) => x.subset(Double), - // Integer(x) => x.get(index).map(Integer), - // Logical(x) => x.get(index).map(Logical), - // Character(x) => x.get(index).map(Character), - // } + use Vector::*; + match self { + Double(x) => x + .set_subset(subset, value.try_into()?) + .map(|x| Double(Rep::from(vec![x]))), + Integer(x) => x + .set_subset(subset, value.try_into()?) + .map(|x| Integer(Rep::from(vec![x]))), + Character(x) => x + .set_subset(subset, value.try_into()?) + .map(|x| Character(Rep::from(vec![x]))), + Logical(x) => x + .set_subset(subset, value.try_into()?) + .map(|x| Logical(Rep::from(vec![x]))), + } } /// Iterate over the names of the vector. @@ -160,16 +167,16 @@ impl Vector { } } - pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { - // This method will be needed when we have scalars - todo!() - } + // pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { + // // This method will be needed when we have scalars + // todo!() + // } - pub fn try_get_inner(&self, index: Obj) -> EvalResult { - // This method will be needed when we have scalars - #[allow(clippy::map_clone)] - self.try_get_inner_mut(index).map(|v| v.clone()) - } + // pub fn try_get_inner(&self, index: Obj) -> EvalResult { + // // This method will be needed when we have scalars + // #[allow(clippy::map_clone)] + // self.try_get_inner_mut(index).map(|v| v.clone()) + // } pub fn subset(&self, subset: Subset) -> Self { match self { @@ -988,3 +995,18 @@ impl std::ops::BitAnd for Vector { } } } + +#[cfg(test)] + +mod tests { + use crate::{r, r_expect}; + + #[test] + fn double_brackets_assign() { + r_expect! {{" + x = c(1, 2) + x[[1]] = 10 + x[[1]] == 10 & x[[2]] == 2 + "}} + } +} diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 16d4709d..f996bf9d 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -3,8 +3,8 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::{Naming, RepType}; use super::reptype::RepTypeIntoIterable; +use super::reptype::{Naming, RepType}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 5fe5aa08..0d5539b4 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -132,7 +132,7 @@ impl RepType { let self_subset = self.subset(subset); match self_subset { RepType::Subset(..) => { - let mut iter = self.iter_subset_indices(); + let mut iter = self_subset.iter_subset_indices(); if let Some(i) = iter.next() { // iter.next() @@ -140,6 +140,7 @@ impl RepType { // TODO: subsetting with NA should not be possible. let i = i.unwrap(); + dbg!(i); Ok(self.with_inner_mut(|values| values[i].view_mut())) } else { @@ -477,9 +478,6 @@ impl RepType { } pub fn iter_subset_indices(&self) -> Box>> { - // TODO: Why do we have to do -1 here. Shouldnt' .filter() and the Iterator method of NamedSubsets - // not already return the 0-based indices? - // TODO: This function is crucial to fix match self.clone() { RepType::Subset(vals, subsets, maybe_naming) => { if subsets.is_empty() { @@ -487,12 +485,7 @@ impl RepType { } if let Some(naming) = maybe_naming { - Box::new( - subsets - .bind_names(naming.map) - .into_iter() - .map(|(x, y)| y), - ) + Box::new(subsets.bind_names(naming.map).into_iter().map(|(_, y)| y)) } else { Box::new(subsets.into_iter().map(|(_, y)| y)) } @@ -502,18 +495,20 @@ impl RepType { /// Reindex the mapping from names to indices. pub fn reindex(&mut self) { - if let RepType::Subset(.., Some(naming)) = self { naming.map.with_inner_mut(|map| { - map.drain(); - - for (i, maybe_name) in naming.names.borrow().iter().enumerate() { - if let OptionNA::Some(name) = maybe_name { - let indices = map.entry(name.clone()).or_default(); - if !indices.contains(&i) { - indices.push(i) + if let RepType::Subset(.., Some(naming)) = self { + naming.map.with_inner_mut(|map| { + map.drain(); + + for (i, maybe_name) in naming.names.borrow().iter().enumerate() { + if let OptionNA::Some(name) = maybe_name { + let indices = map.entry(name.clone()).or_default(); + if !indices.contains(&i) { + indices.push(i) + } } } - } - }) } + }) + } } pub fn dedup_last(self) -> Self { diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index a04c359b..794375d9 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -150,7 +150,6 @@ impl IntoIterator for Subsets { #[cfg(test)] mod test { - use crate::object::Vector; @@ -259,10 +258,7 @@ mod test { use std::rc::Rc; let v = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec![1, 2, 3] - .into_iter() - .map(Integer::Some) - .collect(), + vec![1, 2, 3].into_iter().map(Integer::Some).collect(), )))); let n = CowObj::new(Rc::new(RefCell::new(Rc::new( vec!["a".to_string(), "b".to_string(), "c".to_string()] diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index fec490c9..6c8f7229 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -1,5 +1,8 @@ use super::coercion::AtomicMode; use super::OptionNA; +use crate::error::Error; +use crate::object::Obj; +use crate::object::Vector; pub type Double = OptionNA; impl AtomicMode for Double { @@ -28,3 +31,79 @@ impl AtomicMode for Character { true } } + +impl TryFrom for Double { + type Error = Error; + fn try_from(value: Obj) -> Result { + let err = Err(Error::Other( + "Cannot convert object to scalar double.".to_string(), + )); + if let Obj::Vector(Vector::Double(v)) = value { + if v.len() == 1 { + let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); + return Ok(x.into()); + } else { + return err; + } + } else { + return err; + } + } +} + +impl TryFrom for Integer { + type Error = Error; + fn try_from(value: Obj) -> Result { + let err = Err(Error::Other( + "Cannot convert object to scalar double.".to_string(), + )); + if let Obj::Vector(Vector::Integer(v)) = value { + if v.len() == 1 { + let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); + return Ok(x.into()); + } else { + return err; + } + } else { + return err; + } + } +} + +impl TryFrom for Character { + type Error = Error; + fn try_from(value: Obj) -> Result { + let err = Err(Error::Other( + "Cannot convert object to scalar double.".to_string(), + )); + if let Obj::Vector(Vector::Character(v)) = value { + if v.len() == 1 { + let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); + return Ok(x.into()); + } else { + return err; + } + } else { + return err; + } + } +} + +impl TryFrom for Logical { + type Error = Error; + fn try_from(value: Obj) -> Result { + let err = Err(Error::Other( + "Cannot convert object to scalar double.".to_string(), + )); + if let Obj::Vector(Vector::Logical(v)) = value { + if v.len() == 1 { + let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); + return Ok(x.into()); + } else { + return err; + } + } else { + return err; + } + } +} From 3c2fcf95d35ebee17b511bace86209f31fb1b0bd Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 2 Oct 2024 20:13:56 +0530 Subject: [PATCH 29/49] some more changes --- src/callable/builtins.rs | 5 +- src/callable/core.rs | 8 +- src/callable/primitive/all.rs | 96 ++++++++++ src/callable/primitive/c.rs | 54 +++--- src/callable/primitive/is_na.rs | 89 ++++++++++ src/callable/primitive/is_null.rs | 69 +++++++ src/callable/primitive/mod.rs | 6 + src/callable/primitive/names.rs | 2 +- src/callable/primitive/paste.rs | 6 - src/callable/primitive/sum.rs | 7 +- src/lang.rs | 45 ++--- src/object/core.rs | 4 +- src/object/environment.rs | 2 +- src/object/list.rs | 286 +++--------------------------- src/object/vector/rep.rs | 25 ++- src/object/vector/reptype.rs | 53 +++++- src/object/vector/subsets.rs | 6 +- src/object/vector/types.rs | 6 + 18 files changed, 424 insertions(+), 345 deletions(-) create mode 100644 src/callable/primitive/all.rs create mode 100644 src/callable/primitive/is_na.rs create mode 100644 src/callable/primitive/is_null.rs diff --git a/src/callable/builtins.rs b/src/callable/builtins.rs index 26857893..5404fa1e 100644 --- a/src/callable/builtins.rs +++ b/src/callable/builtins.rs @@ -4,7 +4,7 @@ /// use hashbrown::HashMap; -use ::lazy_static::lazy_static; +use lazy_static::lazy_static; use crate::callable::core::Builtin; use crate::callable::operators::*; @@ -40,10 +40,13 @@ lazy_static! { ("..", Box::new(PostfixPack) as Box), ("[[", Box::new(PostfixIndex) as Box), ("[", Box::new(PostfixVecIndex) as Box), + ("all", Box::new(PrimitiveAll) as Box), ("c", Box::new(PrimitiveC) as Box), ("callstack", Box::new(PrimitiveCallstack) as Box), ("environment", Box::new(PrimitiveEnvironment) as Box), ("eval", Box::new(PrimitiveEval) as Box), + ("is_na", Box::new(PrimitiveIsNA) as Box), + ("is_null", Box::new(PrimitiveIsNull) as Box), ("length", Box::new(PrimitiveLength) as Box), ("list", Box::new(PrimitiveList) as Box), ("names", Box::new(PrimitiveNames) as Box), diff --git a/src/callable/core.rs b/src/callable/core.rs index feea9f03..bbe32b40 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -50,7 +50,7 @@ pub trait Callable { let mut indices: Vec = Vec::new(); - for (i, (maybe_name, value)) in args.pairs().iter().enumerate() { + for (i, (maybe_name, value)) in args.pairs_ref().iter().enumerate() { if let Character::Some(name) = maybe_name { if let Some((Some(_), _)) = formals.remove_named(name) { matched_args.push_named(Character::Some(name.clone()), value.clone()); @@ -62,7 +62,7 @@ pub trait Callable { } println!("matched_args start"); - for (key, _) in matched_args.pairs().iter() { + for (key, _) in matched_args.pairs_ref().iter() { dbg!(key); } println!("matched_args end"); @@ -78,7 +78,7 @@ pub trait Callable { // } // println!("matching args end"); println!("args start"); - for (maybe_name, _) in args.pairs().iter() { + for (maybe_name, _) in args.pairs_ref().iter() { dbg!(&maybe_name); } println!("args end"); @@ -303,7 +303,7 @@ impl TryFrom<&str> for Box { pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. - vals.pairs() + vals.pairs_ref() .iter() .map(|(a, b)| (a.clone(), b.clone())) .map(|(k, v)| match (k, v.force(stack)) { diff --git a/src/callable/primitive/all.rs b/src/callable/primitive/all.rs new file mode 100644 index 00000000..1e172b2f --- /dev/null +++ b/src/callable/primitive/all.rs @@ -0,0 +1,96 @@ +use lazy_static::lazy_static; +use r_derive::*; + +use crate::callable::core::*; +use crate::error::Error; +use crate::lang::*; +use crate::object::reptype::RepType; +use crate::object::types::Logical; +use crate::object::*; + +lazy_static! { + pub static ref FORMALS: ExprList = + ExprList::from(vec![(Some("x".to_string()), Expr::Missing),]); +} + +/// All true? +/// +/// Checks whether all values of a logical vector are true. +/// +/// # In-Language +/// +/// ## Usage +/// +/// ```custom,{class=r} +/// all(x) +/// ``` +/// +/// ## Arguments +/// +/// `x`: Logical vector to check. +/// +/// ## Examples +/// +/// Evaluate code as though it were executed in the current environment. +/// +/// ```custom,{class=r-repl} +/// all([true, false]) +/// all([true, na, false]) +/// all([true, true]) +/// ``` +/// ## Deviations from R +/// The function performs no conversions and expects all arguments to be of type logical. +#[doc(alias = "all")] +#[builtin(sym = "all")] +#[derive(Debug, Clone, PartialEq)] +pub struct PrimitiveAll; +impl Callable for PrimitiveAll { + fn formals(&self) -> ExprList { + FORMALS.clone() + } + + fn call_matched(&self, args: List, _ellipsis: List, stack: &mut CallStack) -> EvalResult { + let x = Obj::List(args).try_get_named("x")?.force(stack)?; + + let mut all = Logical::Some(true); + + if let Obj::Vector(Vector::Logical(v)) = x { + for val in v.values_ref().iter() { + if let Logical::Some(x) = val { + if !x { + return EvalResult::Ok(vec![Logical::Some(false)].into()); + } + } else { + all = Logical::NA; + } + } + } else { + let msg = "Argument 'x' should be logical vector."; + return Error::Other(msg.into()).into(); + } + return EvalResult::Ok(vec![all].into()); + } +} + +#[cfg(test)] +mod tests { + use crate::{r, r_expect}; + #[test] + fn all_true() { + r_expect!(all([true, true])); + } + #[test] + fn not_all_true() { + r_expect!(all([true, false])); + r_expect!(all([na, false])); + r_expect!(all([false, na])); + } + #[test] + fn na() { + r_expect!(all([true, true])) + } + #[test] + fn all_error() { + todo!() + } +} diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index c0b194e1..58fce060 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -52,7 +52,7 @@ impl Callable for PrimitiveC { // lets first see what we're aiming to build. let ty: u8 = vals - .pairs() + .pairs_ref() .iter() .map(|(_, v)| match v { Obj::Null => 0, @@ -63,7 +63,7 @@ impl Callable for PrimitiveC { .fold(0, std::cmp::max); // if the output will have names - let named = vals.pairs().iter().any(|(n, o)| { + let named = vals.pairs_ref().iter().any(|(n, o)| { if matches!(n, OptionNA::Some(_)) { return true; } @@ -86,7 +86,7 @@ impl Callable for PrimitiveC { } let names: Option> = if named { - let mut pairs = vals.pairs(); + let mut pairs = vals.pairs_ref(); let nms = pairs.iter().flat_map(|(name, obj)| { let maybe_prefix = name.clone().as_option().clone(); @@ -120,7 +120,7 @@ impl Callable for PrimitiveC { }; let ret = vals - .pairs() + .pairs_ref() .iter() .map(|(_, r)| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), @@ -145,47 +145,45 @@ impl Callable for PrimitiveC { Vector::Character(_) => Vector::from( Vec::>::new() .into_iter() - .chain(vals.pairs().iter().flat_map( - |(_, i)| match i.clone().as_character() { + .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { + match i.clone().as_character() { Ok(Obj::Vector(Vector::Character(v))) => v.into_iter_values(), _ => unreachable!(), + } + })) + .collect::>(), + ), + Vector::Double(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.pairs_ref().iter().flat_map( + |(_, i)| match i.clone().as_double() { + Ok(Obj::Vector(Vector::Double(v))) => v.into_iter_values(), + _ => unreachable!(), }, )) - .collect::>(), + .collect::>(), ), - Vector::Double(_) => { - Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.pairs().iter().flat_map( - |(_, i)| match i.clone().as_double() { - Ok(Obj::Vector(Vector::Double(v))) => v.into_iter_values(), - _ => unreachable!(), - }, - )) - .collect::>(), - ) - } Vector::Integer(_) => Vector::from( Vec::>::new() .into_iter() - .chain(vals.pairs().iter().flat_map( - |(_, i)| match i.clone().as_integer() { + .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { + match i.clone().as_integer() { Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter_values(), _ => unreachable!(), - }, - )) + } + })) .collect::>(), ), Vector::Logical(_) => Vector::from( Vec::>::new() .into_iter() - .chain(vals.pairs().iter().flat_map( - |(_, i)| match i.clone().as_logical() { + .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { + match i.clone().as_logical() { Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter_values(), _ => unreachable!(), - }, - )) + } + })) .collect::>(), ), }; diff --git a/src/callable/primitive/is_na.rs b/src/callable/primitive/is_na.rs new file mode 100644 index 00000000..4dbe3bbf --- /dev/null +++ b/src/callable/primitive/is_na.rs @@ -0,0 +1,89 @@ +use lazy_static::lazy_static; +use r_derive::*; + +use crate::callable::core::*; +use crate::error::*; +use crate::lang::*; +use crate::object::types::Logical; +use crate::object::*; + +lazy_static! { + pub static ref FORMALS: ExprList = ExprList::from(vec![(Some("x".to_string()), Expr::Missing)]); +} + +/// Is an object NA? +/// +/// Checks whether an object is NA (Not Available) +/// +/// # In-Language +/// +/// ## Usage +/// +/// ```custom,{class=r} +/// is_na(x) +/// ``` +/// +/// ## Arguments +/// +/// `x`: Object to check. +/// +/// ## Examples +/// +/// ```custom,{class=r-repl} +/// is_na(NA) +/// is_na(c(1, NA, 3)) +/// ``` +#[doc(alias = "is_na")] +#[builtin(sym = "is_na")] +#[derive(Debug, Clone, PartialEq)] +pub struct PrimitiveIsNA; + +impl Callable for PrimitiveIsNA { + fn formals(&self) -> ExprList { + FORMALS.clone() + } + + fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult { + let (args, _ellipsis) = self.match_arg_exprs(args, stack)?; + let mut args = Obj::List(args); + + let x = args.try_get_named("x")?.force(stack)?; + + match x { + Obj::Vector(v) => { + let result: Vec = match v { + Vector::Logical(rep) => rep + .values_ref() + .iter() + .map(|x| Logical::Some(x.is_na())) + .collect(), + Vector::Integer(rep) => rep + .values_ref() + .iter() + .map(|x| Logical::Some(x.is_na())) + .collect(), + Vector::Double(rep) => rep + .values_ref() + .iter() + .map(|x| Logical::Some(x.is_na())) + .collect(), + Vector::Character(rep) => rep + .values_ref() + .iter() + .map(|x| Logical::Some(x.is_na())) + .collect(), + }; + Ok(Obj::Vector(Vector::Logical(result.into()))) + } + _ => Err(Error::ArgumentInvalid("x".to_string()).into()), + } + } +} + +#[cfg(test)] + +mod tests { + use crate::{r, r_expect}; + // #[test] + // todo +} diff --git a/src/callable/primitive/is_null.rs b/src/callable/primitive/is_null.rs new file mode 100644 index 00000000..185d187e --- /dev/null +++ b/src/callable/primitive/is_null.rs @@ -0,0 +1,69 @@ +use lazy_static::lazy_static; +use r_derive::*; + +use crate::callable::core::*; +use crate::lang::*; +use crate::object::types::Logical; +use crate::object::*; + +lazy_static! { + pub static ref FORMALS: ExprList = + ExprList::from(vec![(Some("x".to_string()), Expr::Missing),]); +} + +/// Is an object `null` +/// +/// Checks whether an object is null +/// +/// # In-Language +/// +/// ## Usage +/// +/// ```custom,{class=r} +/// is_null(x) +/// ``` +/// +/// ## Arguments +/// +/// `x`: Object to check. +/// +/// ## Examples +/// +/// ```custom,{class=r-repl} +/// is_null(null) +/// is_null(1) +/// ``` +#[doc(alias = "is_null")] +#[builtin(sym = "is_null")] +#[derive(Debug, Clone, PartialEq)] +pub struct PrimitiveIsNull; +impl Callable for PrimitiveIsNull { + fn formals(&self) -> ExprList { + FORMALS.clone() + } + + fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult { + let (args, _ellipsis) = self.match_arg_exprs(args, stack)?; + let mut args = Obj::List(args); + + let x = args.try_get_named("x")?.force(stack)?; + + EvalResult::Ok(Obj::Vector(Vector::from(vec![Logical::Some(matches!( + x, + Obj::Null + ))]))) + } +} + +#[cfg(test)] +mod tests { + use crate::{r, r_expect}; + #[test] + fn is_null() { + r_expect!(is_null(null)) + } + #[test] + fn is_not_null() { + r_expect!(is_null(1:2)) + } +} diff --git a/src/callable/primitive/mod.rs b/src/callable/primitive/mod.rs index 4b638978..e8f01d01 100644 --- a/src/callable/primitive/mod.rs +++ b/src/callable/primitive/mod.rs @@ -30,3 +30,9 @@ mod sum; pub use sum::PrimitiveSum; mod length; pub use length::PrimitiveLength; +mod is_null; +pub use is_null::PrimitiveIsNull; +mod all; +pub use all::PrimitiveAll; +mod is_na; +pub use is_na::PrimitiveIsNA; diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 1041923e..b8e9e721 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -71,7 +71,7 @@ impl Callable for PrimitiveNames { Expr(..) => Ok(Null), // handle arg lists? Function(..) => Ok(Null), // return formals? List(x) => { - Ok(x.pairs() + Ok(x.pairs_ref() .iter() .map(|(k, _)| match k { Character::Some(name) => OptionNA::Some(name.clone()), diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index b8699c13..9177fa25 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -59,12 +59,6 @@ impl Callable for PrimitivePaste { let ellipsis = force_promises(ellipsis, stack)?; - println!("ellipsis start"); - for x in &ellipsis { - dbg!(&x.1); - } - println!("ellipsis end"); - let args = force_promises(args, stack)?; let mut sep = String::from(" "); diff --git a/src/callable/primitive/sum.rs b/src/callable/primitive/sum.rs index 01ab7614..3cfea75e 100644 --- a/src/callable/primitive/sum.rs +++ b/src/callable/primitive/sum.rs @@ -1,3 +1,4 @@ +use lazy_static::lazy_static; use r_derive::*; use crate::callable::core::*; @@ -7,6 +8,10 @@ use crate::lang::*; use crate::object::reptype::RepType; use crate::object::*; +lazy_static! { + pub static ref FORMALS: ExprList = ExprList::from(vec![(None, Expr::Ellipsis(None)),]); +} + /// Calculate a Sum of Elements /// /// # In-Language @@ -34,7 +39,7 @@ pub struct PrimitiveSum; impl Callable for PrimitiveSum { fn formals(&self) -> ExprList { - ExprList::from(vec![(None, Expr::Ellipsis(None))]) + FORMALS.clone() } fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult { diff --git a/src/lang.rs b/src/lang.rs index 22371b9c..5968ad94 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -94,21 +94,7 @@ impl Obj { } } - pub fn replace(&self, value: Obj) -> EvalResult { - todo!() - // For [[-assignment. - // e.g. list(list(1, 2))[[1]] = list(2) should not be vectorized. - // use crate::object::Vector; - // match (self, value) { - // (Obj::List(l), r) => l.replace(r), - // (Obj::Vector(l), Obj::Vector(r)) => match (l, r) { - // (Double(l), Double(r)) => todo!(), - // }, - // _ => unimplemented!(), - // } - // self - } - + // this is vectorized assignment. pub fn assign(self, value: Obj) -> EvalResult { // TODO(ERROR) cleanup let err = Error::Other("Invalid target for assignment".to_string()); @@ -119,13 +105,20 @@ impl Obj { Ok(value) } Obj::List(mut l) => { - // - if let Obj::List(x) = value.clone() { - l.assign(x); - Ok(value) - } else { - Err(err.into()) - } + let v = match value.clone() { + // what about recycling, is this needed here? + // todo: + // x= list(1, 2) + // x[1:2] = c(10, 11) is vectorized in R. + Obj::List(x) => { + println!("Heeere"); + x + } + _ => return Err(err.into()), + }; + + l.assign(v); + Ok(value) } _ => Err(err.into()), } @@ -241,7 +234,7 @@ impl Obj { pub fn get_named(&mut self, name: &str) -> Option { match self { Obj::List(v) => v - .pairs() + .pairs_ref() .iter() .find(|(k, _)| *k == &Character::Some(String::from(name))) .map(|(_, v)| v.clone()), @@ -253,10 +246,6 @@ impl Obj { } } - pub fn set_subset(&mut self, subset: Subset, value: Obj) -> EvalResult { - todo!() - } - // use set_subset instead pub fn set_named(&mut self, name: &str, value: Obj) -> EvalResult { todo!() @@ -399,7 +388,7 @@ impl Display for Obj { } fn display_list(x: &List, f: &mut fmt::Formatter<'_>, bc: Option) -> fmt::Result { - for (i, (maybe_name, value)) in x.pairs().iter().enumerate() { + for (i, (maybe_name, value)) in x.pairs_ref().iter().enumerate() { if i > 0 { writeln!(f)? } diff --git a/src/object/core.rs b/src/object/core.rs index ea7607fd..766a8fce 100644 --- a/src/object/core.rs +++ b/src/object/core.rs @@ -26,9 +26,9 @@ impl PartialEq for Obj { match (self, other) { (Obj::Null, Obj::Null) => true, (Obj::List(l), Obj::List(r)) => l - .pairs() + .pairs_ref() .iter() - .zip(r.pairs().iter()) + .zip(r.pairs_ref().iter()) .all(|((lk, lv), (rk, rv))| lk == rk && lv == rv), (Obj::Expr(l), Obj::Expr(r)) => l == r, (Obj::Promise(None, lc, lenv), Obj::Promise(None, rc, renv)) => { diff --git a/src/object/environment.rs b/src/object/environment.rs index 71ecc05d..2f8983d7 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -56,7 +56,7 @@ impl Environment { } pub fn append(&self, l: List) { - for (key, value) in l.pairs().iter() { + for (key, value) in l.pairs_ref().iter() { if let Character::Some(name) = key { self.values.borrow_mut().insert(name.clone(), value.clone()); } diff --git a/src/object/list.rs b/src/object/list.rs index e0311a9c..a863e241 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -1,270 +1,8 @@ use crate::object::rep::Rep; - -use super::*; +use crate::object::Obj; pub type List = Rep; -// type ListNameMap = HashMap>; - -// #[derive(Debug, Clone, PartialEq, Default)] -// pub struct List { -// pub names: CowObj, -// pub values: CowObj, Obj)>>, -// pub subsets: Subsets, -// } - -// impl List { -// pub fn reindex(&mut self) { -// self.names.with_inner_mut(|names| { -// names.drain(); - -// for (i, (k, _)) in self.values.borrow().iter().enumerate() { -// if let Some(name) = k { -// let indices = names.entry(name.clone()).or_default(); -// if !indices.contains(&i) { -// indices.push(i) -// } -// } -// } -// }) -// } - -// pub fn subset(&self, by: Subset) -> List { -// let Subsets(mut inner) = self.subsets.clone(); -// inner.push(by); -// List { -// names: self.names.clone(), -// values: self.values.view_mut(), -// subsets: Subsets(inner), -// } -// } - -// pub fn assign(&mut self, value: Obj) -> EvalResult { -// match value { -// // remove elements from list -// Obj::Null => { -// let n = self.values.len(); -// let indices = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .take(n); - -// self.values.with_inner_mut(|values| { -// for (i, _) in indices { -// values.remove(i); -// } -// }); - -// self.reindex(); - -// // TODO(feat): need to return list with NULL elements when -// // index is NA - -// Ok(Obj::List(List { -// names: self.names.clone(), -// values: self.values.clone(), -// subsets: self.subsets.clone(), -// })) -// } - -// // any single length R value -// any if any.len() == Some(1) => { -// let n = self.values.len(); -// let indices = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .take(n); - -// self.values.with_inner_mut(|v| { -// // first check to see if we need to extend -// if let Some(max) = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .map(|(i, _)| i) -// .max() -// { -// v.reserve(max.saturating_sub(n)) -// } - -// // then assign to indices -// for (_, i) in indices { -// if let Some(i) = i { -// v[i].1 = any.clone() -// } -// } -// }); - -// Ok(Obj::List(List { -// names: self.names.clone(), -// values: self.values.clone(), -// subsets: self.subsets.clone(), -// })) -// } -// // vectorized assignment -// // TODO(feature): warn when index recycling does not cycle evenly -// any if any.len() == Some(self.len()) => { -// let n = self.values.len(); -// let indices = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .take(n); - -// self.values.with_inner_mut(|v| { -// // first check to see if we need to extend -// if let Some(max) = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .map(|(i, _)| i) -// .max() -// { -// v.reserve(max.saturating_sub(n)) -// } - -// // then assign to indices -// for (any_i, (_, i)) in indices.enumerate() { -// if let (Some(value), Some(i)) = (any.get(any_i), i) { -// v[i].1 = value; -// } -// } -// }); - -// Ok(Obj::List(List { -// names: self.names.clone(), -// values: self.values.clone(), -// subsets: self.subsets.clone(), -// })) -// } -// other => { -// let n = self.values.len(); -// let indices = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .take(n); - -// self.values.with_inner_mut(|v| { -// // first check to see if we need to extend -// if let Some(max) = self -// .subsets -// .clone() -// .bind_names(self.names.clone()) -// .into_iter() -// .map(|(i, _)| i) -// .max() -// { -// v.reserve(max.saturating_sub(n)) -// } - -// // then assign to indices -// for (_, i) in indices { -// if let Some(i) = i { -// v[i].1 = other.clone() -// } -// } -// }); - -// Ok(Obj::List(List { -// names: self.names.clone(), -// values: self.values.clone(), -// subsets: self.subsets.clone(), -// })) -// } -// } -// } - -// pub fn try_get(&self, index: Obj) -> EvalResult { -// let err = Error::Other("Cannot use object for indexing".to_string()); -// match index.as_vector()? { -// Obj::Vector(v) => Ok(Obj::List(self.subset(v.try_into()?))), -// _ => Err(err.into()), -// } -// } - -// pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { -// let err_invalid = Error::Other("Cannot use object for indexing".to_string()); -// let err_index_invalid = Error::Other("Index out of bounds".to_string()); - -// match index.as_vector()? { -// Obj::Vector(v) if v.len() == 1 => { -// let Subsets(mut subsets) = self.subsets.clone(); -// subsets.push(v.try_into()?); - -// if let Some((i, _)) = Subsets(subsets) -// .bind_names(self.names.clone()) -// .into_iter() -// .next() -// { -// self.values.with_inner_mut(|v| { -// v.get_mut(i) -// .map_or(Err(err_index_invalid.into()), |(_, i)| Ok(i.view_mut())) -// }) -// } else { -// Ok(Obj::Null) -// } -// } -// _ => Err(err_invalid.into()), -// } -// } - -// pub fn try_get_inner(&self, index: Obj) -> EvalResult { -// #[allow(clippy::map_clone)] -// self.try_get_inner_mut(index).map(|v| v.clone()) -// } - -// pub fn dedup_last(self) -> Self { -// self.names.with_inner_mut(|names| { -// let mut dups: Vec = names -// .iter() -// .flat_map(|(_, indices)| { -// indices -// .split_last() -// .map_or(vec![], |(_, leading_dups)| leading_dups.to_vec()) -// }) -// .collect(); - -// dups.sort(); - -// self.values.with_inner_mut(|vs| { -// for i in dups.into_iter().rev() { -// vs.remove(i); -// } -// }); -// }); - -// self.names.with_inner_mut(|names| { -// for (_, indices) in names.iter_mut() { -// indices.drain(0..indices.len()); -// } -// }); - -// self -// } - -// pub fn len(&self) -> usize { -// let Subsets(inner) = &self.subsets; -// match inner.as_slice() { -// [] => self.values.borrow().len(), -// [.., last] => std::cmp::min(self.values.borrow().len(), last.len()), -// } -// } - -// #[must_use] -// pub fn is_empty(&self) -> bool { -// self.len() == 0 -// } -// } - #[cfg(test)] mod tests { use crate::{r, r_expect}; @@ -290,7 +28,7 @@ mod tests { r_expect! {{r#" l1 = (a = 1,) l2 = l1 - l1["a"] = 2 + l1[["a"]] = 2 l1$a == 2 & l2$a == 1 "#}} } @@ -299,7 +37,7 @@ mod tests { r_expect! {{r#" l = (a = 1, b = 2, c = 3) l1 = l - l1[c("a", "b")] = c(10, 20) + l1[c("a", "b")] = (10, 20) l1$a == 10 && l1$b == 20 & l$a == 1 & l$b == 2 "#}} @@ -309,7 +47,7 @@ mod tests { r_expect! {{" l = (1, 2) l1 = l - l1[1:2] = [10, 20] + l1[1:2] = (10, 20) l1[[1]] == 10 && l1[[2]] == 20 & l[[1]] == 1 & l[[2]] == 2 "}} } @@ -367,4 +105,20 @@ mod tests { l[[1]] == 1 "#}} } + #[test] + fn dont_convert_atomic() { + r_expect! {{r#" + l = (1, ) + l[1] = [1, 2] + l[[1]][1] == 1 & l[[1]][2] == + "#}} + } + #[test] + fn assign_null() { + r_expect! {{r#" + l = (1, ) + l[[1]] = null + is_null(l[[1]]) + "#}} + } } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index f996bf9d..ec504fb2 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -3,8 +3,8 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::RepTypeIntoIterable; use super::reptype::{Naming, RepType}; +use super::reptype::{RepTypeIntoIterable, RepTypeIntoIterableValues}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; @@ -51,7 +51,7 @@ impl Rep { } impl Rep { - /// Iterate over the names and values of the vector (if the names exist). + /// Iterate over the owned names and values of the vector. pub fn iter_pairs(&self) -> RepTypeIterPairs { // FIXME: This should maybe return an option self.0.borrow().clone().iter_pairs() @@ -177,8 +177,12 @@ where todo!() } - pub fn pairs(&self) -> RepTypeIntoIterable { - self.0.borrow().iterable() + pub fn pairs_ref(&self) -> RepTypeIntoIterable { + self.0.borrow().pairs_ref() + } + + pub fn values_ref(&self) -> RepTypeIntoIterableValues { + self.0.borrow().values_ref() } // pub fn iter_subset_indices(&self) -> Box)>> { @@ -424,6 +428,19 @@ where } } +// impl From for Rep +// where +// T: Clone + Default, +// { +// fn from(x: T) -> Self { +// Rep(RefCell::new(RepType::Subset( +// vec![x].into(), +// Subsets::default(), +// None, +// ))) +// } +// } + impl From> for Rep where T: Clone + Default, diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 0d5539b4..730f3b58 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -45,7 +45,7 @@ impl Naming { pub fn push_name(&self, name: OptionNA) { self.names.with_inner_mut(|v| v.push(name.clone())); if let OptionNA::Some(name) = name { - let n = self.names.len(); + let n = self.names.len() - 1; self.map.with_inner_mut(|map| { let indices = map.entry(name.clone()).or_default(); if !indices.contains(&n) { @@ -191,6 +191,24 @@ where } } +pub struct RepTypeIntoIterableValues { + values: Rc>, + na_value: T, + iter: Box>>, +} + +impl RepTypeIntoIterableValues { + pub fn iter(&mut self) -> RepTypeIterableValues<'_, T> { + let values = &self.values[..]; + + RepTypeIterableValues { + values, + na_value: &self.na_value, + iter: &mut self.iter, + } + } +} + pub struct RepTypeIntoIterable { values: Rc>, names: Option>>, @@ -215,6 +233,12 @@ impl RepTypeIntoIterable { } } +pub struct RepTypeIterableValues<'a, T: Clone> { + values: &'a [T], + na_value: &'a T, + iter: &'a mut Box>>, +} + pub struct RepTypeIterable<'a, T: Clone> { values: &'a [T], names: Option<&'a [Character]>, @@ -240,6 +264,16 @@ impl<'a, T: Clone> Iterator for RepTypeIterable<'a, T> { } } +impl<'a, T: Clone> Iterator for RepTypeIterableValues<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // FIXME: This panics when subsetting with NA + let i = self.iter.next()?.unwrap(); + Some(&self.values[i]) + } +} + // FIXME: Don't make this an enum but simply different structs for eah reptype. // We yield Box anyway. pub enum RepTypeIter { @@ -364,7 +398,22 @@ impl RepType { } } - pub fn iterable(&self) -> RepTypeIntoIterable { + pub fn values_ref(&self) -> RepTypeIntoIterableValues { + match self.clone() { + RepType::Subset(values, ..) => { + let iter = Box::new(self.iter_subset_indices()); + let values = values.inner_rc(); + + RepTypeIntoIterableValues { + values, + na_value: T::default(), + iter, + } + } + } + } + + pub fn pairs_ref(&self) -> RepTypeIntoIterable { match self.clone() { RepType::Subset(values, _, maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 794375d9..66e04857 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -288,7 +288,11 @@ mod test { let m: CowObj>> = CowObj::new(Rc::new(RefCell::new(Rc::new(m1)))); let naming = Naming { map: m, names: n }; - let x = RepType::Subset(v, Subsets(vec![Subset::Indices(s_indices)]), Option::None); + let x = RepType::Subset( + v, + Subsets(vec![Subset::Names(s_names)]), + Option::Some(naming), + ); for i in x.iter_subset_indices().take(3) { println!("{}", i.unwrap()); } diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index 6c8f7229..db885d71 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -32,6 +32,12 @@ impl AtomicMode for Character { } } +impl OptionNA { + pub fn is_na(&self) -> bool { + matches!(self, OptionNA::NA) + } +} + impl TryFrom for Double { type Error = Error; fn try_from(value: Obj) -> Result { From d0acd9be317171c329c1452b050d4a0cb40d68e4 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 09:30:42 +0200 Subject: [PATCH 30/49] cleanup --- src/callable/builtins.rs | 2 - src/callable/core.rs | 19 ------ src/callable/primitive/all.rs | 96 ------------------------------- src/callable/primitive/is_na.rs | 89 ---------------------------- src/callable/primitive/is_null.rs | 2 +- src/callable/primitive/mod.rs | 4 -- src/lang.rs | 23 ++++++-- src/object/list.rs | 8 +-- src/object/vector/rep.rs | 14 ++++- src/object/vector/reptype.rs | 7 ++- src/object/vector/types.rs | 30 +++++++++- 11 files changed, 67 insertions(+), 227 deletions(-) delete mode 100644 src/callable/primitive/all.rs delete mode 100644 src/callable/primitive/is_na.rs diff --git a/src/callable/builtins.rs b/src/callable/builtins.rs index 5404fa1e..0f8700a1 100644 --- a/src/callable/builtins.rs +++ b/src/callable/builtins.rs @@ -40,12 +40,10 @@ lazy_static! { ("..", Box::new(PostfixPack) as Box), ("[[", Box::new(PostfixIndex) as Box), ("[", Box::new(PostfixVecIndex) as Box), - ("all", Box::new(PrimitiveAll) as Box), ("c", Box::new(PrimitiveC) as Box), ("callstack", Box::new(PrimitiveCallstack) as Box), ("environment", Box::new(PrimitiveEnvironment) as Box), ("eval", Box::new(PrimitiveEval) as Box), - ("is_na", Box::new(PrimitiveIsNA) as Box), ("is_null", Box::new(PrimitiveIsNull) as Box), ("length", Box::new(PrimitiveLength) as Box), ("list", Box::new(PrimitiveList) as Box), diff --git a/src/callable/core.rs b/src/callable/core.rs index bbe32b40..f1e6bfc1 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -57,32 +57,13 @@ pub trait Callable { continue; } } - println!("push it {}", i); indices.push(i as i32); } - println!("matched_args start"); - for (key, _) in matched_args.pairs_ref().iter() { - dbg!(key); - } - println!("matched_args end"); - let indices: Vec = indices.into_iter().map(Integer::Some).collect(); - dbg!(&indices); let subset = Subset::Indices(indices.into()); let args = args.subset(subset).materialize(); - // println!("matching args start"); - // for (maybe_name, _) in args.pairs().iter() { - // dbg!(&maybe_name); - // } - // println!("matching args end"); - println!("args start"); - for (maybe_name, _) in args.pairs_ref().iter() { - dbg!(&maybe_name); - } - println!("args end"); - // TODO(bug): need to evaluate trailing unassigned params that have // a default value before popping off remaining trailing params diff --git a/src/callable/primitive/all.rs b/src/callable/primitive/all.rs deleted file mode 100644 index 1e172b2f..00000000 --- a/src/callable/primitive/all.rs +++ /dev/null @@ -1,96 +0,0 @@ -use lazy_static::lazy_static; -use r_derive::*; - -use crate::callable::core::*; -use crate::error::Error; -use crate::lang::*; -use crate::object::reptype::RepType; -use crate::object::types::Logical; -use crate::object::*; - -lazy_static! { - pub static ref FORMALS: ExprList = - ExprList::from(vec![(Some("x".to_string()), Expr::Missing),]); -} - -/// All true? -/// -/// Checks whether all values of a logical vector are true. -/// -/// # In-Language -/// -/// ## Usage -/// -/// ```custom,{class=r} -/// all(x) -/// ``` -/// -/// ## Arguments -/// -/// `x`: Logical vector to check. -/// -/// ## Examples -/// -/// Evaluate code as though it were executed in the current environment. -/// -/// ```custom,{class=r-repl} -/// all([true, false]) -/// all([true, na, false]) -/// all([true, true]) -/// ``` -/// ## Deviations from R -/// The function performs no conversions and expects all arguments to be of type logical. -#[doc(alias = "all")] -#[builtin(sym = "all")] -#[derive(Debug, Clone, PartialEq)] -pub struct PrimitiveAll; -impl Callable for PrimitiveAll { - fn formals(&self) -> ExprList { - FORMALS.clone() - } - - fn call_matched(&self, args: List, _ellipsis: List, stack: &mut CallStack) -> EvalResult { - let x = Obj::List(args).try_get_named("x")?.force(stack)?; - - let mut all = Logical::Some(true); - - if let Obj::Vector(Vector::Logical(v)) = x { - for val in v.values_ref().iter() { - if let Logical::Some(x) = val { - if !x { - return EvalResult::Ok(vec![Logical::Some(false)].into()); - } - } else { - all = Logical::NA; - } - } - } else { - let msg = "Argument 'x' should be logical vector."; - return Error::Other(msg.into()).into(); - } - return EvalResult::Ok(vec![all].into()); - } -} - -#[cfg(test)] -mod tests { - use crate::{r, r_expect}; - #[test] - fn all_true() { - r_expect!(all([true, true])); - } - #[test] - fn not_all_true() { - r_expect!(all([true, false])); - r_expect!(all([na, false])); - r_expect!(all([false, na])); - } - #[test] - fn na() { - r_expect!(all([true, true])) - } - #[test] - fn all_error() { - todo!() - } -} diff --git a/src/callable/primitive/is_na.rs b/src/callable/primitive/is_na.rs deleted file mode 100644 index 4dbe3bbf..00000000 --- a/src/callable/primitive/is_na.rs +++ /dev/null @@ -1,89 +0,0 @@ -use lazy_static::lazy_static; -use r_derive::*; - -use crate::callable::core::*; -use crate::error::*; -use crate::lang::*; -use crate::object::types::Logical; -use crate::object::*; - -lazy_static! { - pub static ref FORMALS: ExprList = ExprList::from(vec![(Some("x".to_string()), Expr::Missing)]); -} - -/// Is an object NA? -/// -/// Checks whether an object is NA (Not Available) -/// -/// # In-Language -/// -/// ## Usage -/// -/// ```custom,{class=r} -/// is_na(x) -/// ``` -/// -/// ## Arguments -/// -/// `x`: Object to check. -/// -/// ## Examples -/// -/// ```custom,{class=r-repl} -/// is_na(NA) -/// is_na(c(1, NA, 3)) -/// ``` -#[doc(alias = "is_na")] -#[builtin(sym = "is_na")] -#[derive(Debug, Clone, PartialEq)] -pub struct PrimitiveIsNA; - -impl Callable for PrimitiveIsNA { - fn formals(&self) -> ExprList { - FORMALS.clone() - } - - fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult { - let (args, _ellipsis) = self.match_arg_exprs(args, stack)?; - let mut args = Obj::List(args); - - let x = args.try_get_named("x")?.force(stack)?; - - match x { - Obj::Vector(v) => { - let result: Vec = match v { - Vector::Logical(rep) => rep - .values_ref() - .iter() - .map(|x| Logical::Some(x.is_na())) - .collect(), - Vector::Integer(rep) => rep - .values_ref() - .iter() - .map(|x| Logical::Some(x.is_na())) - .collect(), - Vector::Double(rep) => rep - .values_ref() - .iter() - .map(|x| Logical::Some(x.is_na())) - .collect(), - Vector::Character(rep) => rep - .values_ref() - .iter() - .map(|x| Logical::Some(x.is_na())) - .collect(), - }; - Ok(Obj::Vector(Vector::Logical(result.into()))) - } - _ => Err(Error::ArgumentInvalid("x".to_string()).into()), - } - } -} - -#[cfg(test)] - -mod tests { - use crate::{r, r_expect}; - // #[test] - // todo -} diff --git a/src/callable/primitive/is_null.rs b/src/callable/primitive/is_null.rs index 185d187e..696b1756 100644 --- a/src/callable/primitive/is_null.rs +++ b/src/callable/primitive/is_null.rs @@ -64,6 +64,6 @@ mod tests { } #[test] fn is_not_null() { - r_expect!(is_null(1:2)) + r_expect!(!is_null(1:2)) } } diff --git a/src/callable/primitive/mod.rs b/src/callable/primitive/mod.rs index e8f01d01..3e698957 100644 --- a/src/callable/primitive/mod.rs +++ b/src/callable/primitive/mod.rs @@ -32,7 +32,3 @@ mod length; pub use length::PrimitiveLength; mod is_null; pub use is_null::PrimitiveIsNull; -mod all; -pub use all::PrimitiveAll; -mod is_na; -pub use is_na::PrimitiveIsNA; diff --git a/src/lang.rs b/src/lang.rs index 5968ad94..b62f4c6e 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -105,19 +105,32 @@ impl Obj { Ok(value) } Obj::List(mut l) => { - let v = match value.clone() { + match value.clone() { // what about recycling, is this needed here? // todo: // x= list(1, 2) // x[1:2] = c(10, 11) is vectorized in R. - Obj::List(x) => { - println!("Heeere"); - x + Obj::List(r) => { + l.assign(r); } + Obj::Vector(r) => match r { + Vector::Integer(r) => { + l.assign(r); + } + Vector::Character(r) => { + l.assign(r); + } + Vector::Logical(r) => { + l.assign(r); + } + Vector::Double(r) => { + l.assign(r); + } + _ => todo!(), + }, _ => return Err(err.into()), }; - l.assign(v); Ok(value) } _ => Err(err.into()), diff --git a/src/object/list.rs b/src/object/list.rs index a863e241..92f9fa8f 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -106,11 +106,11 @@ mod tests { "#}} } #[test] - fn dont_convert_atomic() { + fn assign_atomic_to_list_slice() { r_expect! {{r#" - l = (1, ) - l[1] = [1, 2] - l[[1]][1] == 1 & l[[1]][2] == + l = (1, 2, 3) + l[1:2] = [3, 4] + l[[1]] == 3 & l[[2]] == 4 "#}} } #[test] diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index ec504fb2..7cb1f9b9 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -285,7 +285,11 @@ where self.borrow().push_named(name, value) } - pub fn assign(&mut self, value: Self) -> Self { + pub fn assign(&mut self, value: Rep) -> Self + where + T: From + Clone, + R: Clone + Default, + { // TODO: Handle names here // The assign method from List had a lot more code, // check that everything is covered here. @@ -388,6 +392,14 @@ where self.as_mode::() } + pub fn try_scalar(&self) -> Result { + if self.len() == 1 { + Ok(self.values_ref().iter().next().cloned().unwrap()) + } else { + Err(Error::Other("Vector is not of length 1".to_string())) + } + } + /// Apply over the vector contents to produce a vector of [std::cmp::Ordering] /// /// This function is used primarily in support of the implementation of diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 730f3b58..b82940d7 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -681,9 +681,10 @@ impl RepType { /// Assignment to a vector from another. The aggregate subsetted indices /// are iterated over while performing the assignment. /// - pub fn assign(&mut self, value: Self) -> Self + pub fn assign(&mut self, value: RepType) -> Self where - T: Clone + Default, + T: Clone + Default + From, + R: Default + Clone, { // TODO(feature): here we should also throw an error if the recycling rules are violated. let l_indices = self.iter_subset_indices(); @@ -697,7 +698,7 @@ impl RepType { for (li, ri) in l_indices.zip(r_indices) { match (li, ri) { (Some(li), None) => lvb[li] = T::default(), - (Some(li), Some(ri)) => lvb[li] = rvb[ri % rvb.len()].clone(), + (Some(li), Some(ri)) => lvb[li] = rvb[ri % rvb.len()].clone().into(), _ => (), } } diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index db885d71..9fd9fb06 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -61,7 +61,7 @@ impl TryFrom for Integer { type Error = Error; fn try_from(value: Obj) -> Result { let err = Err(Error::Other( - "Cannot convert object to scalar double.".to_string(), + "Cannot convert object to scalar integer.".to_string(), )); if let Obj::Vector(Vector::Integer(v)) = value { if v.len() == 1 { @@ -80,7 +80,7 @@ impl TryFrom for Character { type Error = Error; fn try_from(value: Obj) -> Result { let err = Err(Error::Other( - "Cannot convert object to scalar double.".to_string(), + "Cannot convert object to scalar character.".to_string(), )); if let Obj::Vector(Vector::Character(v)) = value { if v.len() == 1 { @@ -99,7 +99,7 @@ impl TryFrom for Logical { type Error = Error; fn try_from(value: Obj) -> Result { let err = Err(Error::Other( - "Cannot convert object to scalar double.".to_string(), + "Cannot convert object to scalar logical.".to_string(), )); if let Obj::Vector(Vector::Logical(v)) = value { if v.len() == 1 { @@ -113,3 +113,27 @@ impl TryFrom for Logical { } } } + +impl From for Vector { + fn from(value: Character) -> Self { + Vector::Character(vec![value].into()) + } +} + +impl From for Vector { + fn from(value: Logical) -> Self { + Vector::Logical(vec![value].into()) + } +} + +impl From for Vector { + fn from(value: Double) -> Self { + Vector::Double(vec![value].into()) + } +} + +impl From for Vector { + fn from(value: Integer) -> Self { + Vector::Integer(vec![value].into()) + } +} From 14f4904e211b03cb68270dcb10705d8d16f3feae Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 14:57:54 +0200 Subject: [PATCH 31/49] ... --- src/callable/core.rs | 13 +-- src/callable/operators.rs | 55 +++++++-- src/callable/primitive/c.rs | 96 +++++++++++++++- src/callable/primitive/mod.rs | 2 + src/callable/primitive/paste.rs | 6 - src/object/list.rs | 7 ++ src/object/vector/core.rs | 28 ++--- src/object/vector/rep.rs | 195 ++++++++++++++++++++++++-------- src/object/vector/reptype.rs | 105 ++++++++++++----- src/object/vector/subset.rs | 36 ------ src/object/vector/types.rs | 39 +++++++ 11 files changed, 423 insertions(+), 159 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index f1e6bfc1..73da7a58 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -46,8 +46,6 @@ pub trait Callable { // assign named args to corresponding formals - let args = args.materialize(); - let mut indices: Vec = Vec::new(); for (i, (maybe_name, value)) in args.pairs_ref().iter().enumerate() { @@ -89,13 +87,8 @@ pub trait Callable { // add back in parameter defaults that weren't filled with args for (param, default) in formals.into_iter() { - let param = if let Some(param) = param { - Character::Some(param) - } else { - Character::NA - }; matched_args.push_named( - param, + param.into(), Obj::Promise(None, default, stack.last_frame().env().clone()), ) } @@ -284,9 +277,7 @@ impl TryFrom<&str> for Box { pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. - vals.pairs_ref() - .iter() - .map(|(a, b)| (a.clone(), b.clone())) + vals.iter_pairs() .map(|(k, v)| match (k, v.force(stack)) { (k, Ok(v)) => Ok((k, v)), (_, Err(e)) => Err(e), diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 1796ff31..f040a020 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -5,7 +5,7 @@ use crate::context::Context; use crate::error::Error; use crate::lang::{CallStack, EvalResult}; use crate::object::types::*; -use crate::object::*; +use crate::{internal_err, object::*}; #[derive(Debug, Clone, PartialEq)] #[builtin(sym = "<-", kind = Infix)] @@ -336,10 +336,13 @@ impl Callable for InfixDollar { unreachable!(); }; - let mut what = stack.eval(what)?; + let what = stack.eval(what)?; match index { - Expr::String(s) | Expr::Symbol(s) => what.try_get_named(s.as_str()), + Expr::String(s) | Expr::Symbol(s) => { + let index = Obj::Vector(Vector::Character(vec![Character::Some(s)].into())); + what.try_get_inner(index) + } _ => Ok(Obj::Null), } } @@ -355,10 +358,13 @@ impl Callable for InfixDollar { unreachable!(); }; - let mut what = stack.eval_mut(what)?; + let what = stack.eval_mut(what)?; match index { - Expr::String(s) | Expr::Symbol(s) => what.try_get_named(s.as_str()), + Expr::String(s) | Expr::Symbol(s) => { + let index = Obj::Vector(Vector::Character(vec![Character::Some(s)].into())); + what.try_get_inner_mut(index) + } _ => Ok(Obj::Null), } } @@ -375,12 +381,15 @@ impl Callable for InfixDollar { }; let value = stack.eval(value)?; - let mut what = stack.eval_mut(what)?; + let what = stack.eval_mut(what)?; match name { Expr::String(s) | Expr::Symbol(s) => { - what.set_named(s.as_str(), value)?; - Ok(what) + let index = Subset::Names(vec![Character::Some(s)].into()); + Ok(match what { + Obj::List(mut v) => v.set_subset(index, value)?, + _ => unimplemented!(), + }) } _ => unimplemented!(), } @@ -409,9 +418,6 @@ impl Callable for PostfixIndex { let x = args.unnamed_binary_args(); let what = stack.eval_mut(x.0)?; let index = stack.eval(x.1)?; - // TODO: Ensure that index is of length 1. - // We cannot call into try_get_inner_mut because not all objects can be modified in-place - // Instead, we internally simply return the slice which can be modified in-place what.try_get_inner_mut(index) } @@ -495,7 +501,7 @@ impl Callable for PrimList { mod tests { use crate::error::Error; use crate::lang::{EvalResult, Signal}; - use crate::r; + use crate::{r, r_expect}; #[test] fn colon_operator() { assert_eq!(EvalResult::Err(Signal::Error(Error::InvalidRange)), r!(1:0)); @@ -503,4 +509,29 @@ mod tests { assert_eq!(r!([1]), r!(1:1)); assert_eq!(r!(1:-2:-3), r!([1, -1, -3])); } + + #[test] + fn dollar_assign() { + r_expect! {{" + l = (a = 1, ) + x = (l$a = 2) + l$a == 2 & x == 2 + "}} + } + #[test] + fn dollar_assign_nested() { + r_expect! {{" + l = (a = (b = 1,),) + x = (l$a$b = 2) + l$a$b == 2 & x == 2 + "}} + } + + #[test] + fn dollar_access() { + r_expect! {{" + l = (a = 1, ) + l$a == 1 + "}} + } } diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index 58fce060..792fde85 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -2,9 +2,9 @@ use r_derive::*; use crate::callable::core::*; use crate::context::Context; -use crate::lang::*; use crate::object::types::*; use crate::object::*; +use crate::{internal_err, lang::*}; /// Concatenate Values /// @@ -57,8 +57,7 @@ impl Callable for PrimitiveC { .map(|(_, v)| match v { Obj::Null => 0, Obj::Vector(_) => 1, - Obj::List(_) => 2, - _ => 0, + _ => 2, }) .fold(0, std::cmp::max); @@ -70,7 +69,7 @@ impl Callable for PrimitiveC { match o { Obj::Vector(v) => v.is_named(), Obj::List(l) => l.is_named(), - _ => todo!(), + _ => false, } }); @@ -82,7 +81,28 @@ impl Callable for PrimitiveC { // most complex type was List // FIXME: handle names if ty == 2 { - return Ok(Obj::List(vals)); + // TODO: We should use size hints here. + let list = List::new(); + for (name1, value1) in vals.iter_pairs() { + match value1 { + Obj::List(x) => { + for (name2, value2) in x.iter_pairs() { + let name = match (&name1, name2) { + (OptionNA::Some(x1), OptionNA::Some(x2)) => { + OptionNA::Some(format!("{x1}.{x2}")) + } + (OptionNA::NA, OptionNA::Some(x2)) => OptionNA::Some(x2), + (OptionNA::Some(_), OptionNA::NA) => name1.clone(), + (OptionNA::NA, OptionNA::NA) => OptionNA::NA, + }; + + list.push_named(name, value2) + } + } + _ => list.push_named(name1, value1), + } + } + return Ok(Obj::List(list)); } let names: Option> = if named { @@ -189,8 +209,72 @@ impl Callable for PrimitiveC { }; if let Some(names) = names { - v.set_names_(names.into()) + v.set_names(names.into()) } Ok(Obj::Vector(v)) } } + +#[cfg(test)] + +mod tests { + use crate::{r, r_expect}; + #[test] + fn list_empty() { + assert_eq!(r!(list()), r!(c(list()))) + } + #[test] + fn list_list() { + r_expect! {{" + l = c(list(1), list(2)) + l[[1]] == 1 & l[[2]] == 2 + "}} + } + #[test] + fn list_vec() { + r_expect! {{" + l = c(list(1), 2:3) + l[[1]] == 1 & l[[2]][1] == 2 & l[[2]][2] == 3 + "}} + } + #[test] + fn list_fn() { + r_expect! {{" + l = c(list(1), fn() 2) + l[[1]] == 1 & l[[2]]() == 2 + "}} + } + #[test] + fn function() { + r_expect! {{" + l = c(fn() 2) + l[[1]]() == 2 + "}} + } + #[test] + fn list_names_outer() { + r_expect! {{" + c(a = list(1))$a == 1 + "}} + } + #[test] + fn list_names_inner() { + r_expect! {{" + c(list(a = 1))$a == 1 + "}} + } + #[test] + fn list_names_both() { + r_expect! {{" + c(a = list(b = 1))$a.b == 1 + "}} + } + + #[test] + fn vector_names() { + r_expect! {{r#" + x = [a = 1] + names(x) == "a" + "#}} + } +} diff --git a/src/callable/primitive/mod.rs b/src/callable/primitive/mod.rs index 3e698957..139373d2 100644 --- a/src/callable/primitive/mod.rs +++ b/src/callable/primitive/mod.rs @@ -32,3 +32,5 @@ mod length; pub use length::PrimitiveLength; mod is_null; pub use is_null::PrimitiveIsNull; +mod capture_output; +pub use capture_output::PrimitiveCaptureOutput; diff --git a/src/callable/primitive/paste.rs b/src/callable/primitive/paste.rs index 9177fa25..73ab4c23 100644 --- a/src/callable/primitive/paste.rs +++ b/src/callable/primitive/paste.rs @@ -95,9 +95,6 @@ impl Callable for PrimitivePaste { } } - dbg!(&collapse); - dbg!(&sep); - // coerce all of our remaining arguments into vectors of strings let vec_s_vec: Vec> = ellipsis .into_iter() @@ -129,12 +126,9 @@ impl Callable for PrimitivePaste { }); }); - dbg!(&output); - if should_collapse { output = vec![output.join(&collapse)]; } - Ok(Obj::Vector(output.into())) } } diff --git a/src/object/list.rs b/src/object/list.rs index 92f9fa8f..31d708e1 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -121,4 +121,11 @@ mod tests { is_null(l[[1]]) "#}} } + #[test] + #[should_panic] + fn index_length_one() { + r_expect! {{r#" + list(1, 2)[[c(1L, 2L)]] + "#}} + } } diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index fd7e4d5c..66e556b6 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -9,6 +9,7 @@ use crate::object::Obj; use super::coercion::CoercibleInto; use super::rep::Rep; use super::reptype::RepType; +use super::reptype::RepTypeIterNames; use super::subset::Subset; use super::types::*; @@ -106,15 +107,14 @@ impl Vector { } /// Iterate over the names of the vector. - pub fn iter_names(&self) -> Option>>> { - todo!() - // use Vector::*; - // match self { - // Double(x) => x.iter_names(), - // Integer(x) => x.iter_names(), - // Logical(x) => x.iter_names(), - // Character(x) => x.iter_names(), - // } + pub fn iter_names(&self) -> Option { + use Vector::*; + match self { + Double(x) => x.iter_names(), + Integer(x) => x.iter_names(), + Logical(x) => x.iter_names(), + Character(x) => x.iter_names(), + } } pub fn is_named(&self) -> bool { @@ -138,12 +138,12 @@ impl Vector { } } - pub fn set_names_(&self, names: CowObj>) { + pub fn set_names(&self, names: CowObj>) { match self { - Vector::Character(x) => x.set_names_(names), - Vector::Logical(x) => x.set_names_(names), - Vector::Integer(x) => x.set_names_(names), - Vector::Double(x) => x.set_names_(names), + Vector::Character(x) => x.set_names(names), + Vector::Logical(x) => x.set_names(names), + Vector::Integer(x) => x.set_names(names), + Vector::Double(x) => x.set_names(names), }; } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 7cb1f9b9..a07e9b5c 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -1,10 +1,11 @@ use std::cell::{Ref, RefCell, RefMut}; use std::fmt::{Debug, Display}; +use std::iter::repeat; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::{Naming, RepType}; -use super::reptype::{RepTypeIntoIterable, RepTypeIntoIterableValues}; +use super::reptype::{Naming, RepType, RepTypeIterNames}; +use super::reptype::{RepTypeIntoIterable, RepTypeIntoIterableNames, RepTypeIntoIterableValues}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; @@ -88,10 +89,10 @@ where // x.into_iter() // } - // /// Iterate over the names of the vector (if they exist). - // pub fn iter_names(&self) -> Option>> { - // self.0.borrow().iter_names() - // } + /// Iterate over the names of the vector (if they exist). + pub fn iter_names(&self) -> Option { + self.0.borrow().iter_names() + } fn materialize_inplace(&self) -> &Self { // TODO: Rewrite this to avoid copying unnecessarily @@ -111,7 +112,7 @@ where } /// Set the names of the vector. - pub fn set_names_(&self, names: CowObj>>) { + pub fn set_names(&self, names: CowObj>>) { let new_repr = self.borrow().materialize().set_names(names); self.0.replace(new_repr); } @@ -185,6 +186,10 @@ where self.0.borrow().values_ref() } + pub fn names_ref(&self) -> Option { + self.0.borrow().names_ref() + } + // pub fn iter_subset_indices(&self) -> Box)>> { // todo!() // } @@ -563,48 +568,148 @@ where return write!(f, "character(0)"); } } - // FIXME: This should use the new rep API - let nlen = format!("{}", n).len(); - // TODO: iteratively calculate when we hit max print so our - // max_len isn't inflated by a value that is omitted - - let xc = self.inner().clone(); - let xb = xc.borrow(); - - let x_strs = xb.iter().map(|xi| format!("{:?}", xi)); - let max_len = x_strs - .clone() - .fold(0, |max_len, xi| std::cmp::max(max_len, xi.len())); - - let mut col = 0; - let gutterlen = 2 + nlen + 1; - - // hard coded max print & console width - let maxprint = 20 * ((80 - gutterlen) / max_len); - - x_strs - .take(maxprint) - .enumerate() - .try_for_each(|(i, x_str)| { - if i == 0 { - col = gutterlen + max_len; - write!(f, "{:>3$}[{}] {:>4$}", "", i + 1, x_str, nlen - 1, max_len) - } else if col + 1 + max_len > 80 { - col = gutterlen + max_len; - let i_str = format!("{}", i + 1); - let gutter = nlen - i_str.len(); - write!(f, "\n{:>3$}[{}] {:>4$}", "", i_str, x_str, gutter, max_len) - } else { - col += 1 + max_len; - write!(f, " {:>1$}", x_str, max_len) + // calculate how many characters are printed per value. + // The iteraror yields the characters needed for a specific item. + fn element_width(iter: impl Iterator) -> usize { + let mut elt_width = 1_usize; + for (i, width) in iter.enumerate() { + elt_width = std::cmp::max(elt_width, width); + if elt_width * (i + 1) >= 20 * 80 { + break; } - })?; - - if n > maxprint { - write!(f, "\n[ omitting {} entries ]", n - maxprint)?; + } + elt_width } + if !self.is_named() { + let elt_width = + element_width(self.values_ref().iter().map(|x| format!("{:?}", x).len())); + // TODO: iteratively calculate when we hit max print so our + // max_len isn't inflated by a value that is omitted + + let mut values_ref = self.values_ref(); + let x_strs = values_ref.iter().map(|xi| format!("{:?}", xi)); + + let mut col = 0; + //| [1] 1 2 3 4 5 6 7 8 9| + //|[10] 10 11 12 13 14 15 16 17 18| + //|-----| + // in the above example the gutterlen is 5 + let gutterlen = 2 + nlen + 1; + + // hard coded max print & console width + // we print at most 20 rows + let maxprint = 20 * ((80 - gutterlen) / (elt_width + 1)); + + x_strs + .take(maxprint) + .enumerate() + .try_for_each(|(i, x_str)| { + if i == 0 { + col = gutterlen + elt_width; + write!( + f, + "{:>3$}[{}] {:>4$}", + "", + i + 1, + x_str, + nlen - 1, + elt_width + ) + } else if col + 1 + elt_width > 80 { + col = gutterlen + elt_width; + let i_str = format!("{}", i + 1); + let gutter = nlen - i_str.len(); + write!( + f, + "\n{:>3$}[{}] {:>4$}", + "", i_str, x_str, gutter, elt_width + ) + } else { + col += 1 + elt_width; + write!(f, " {:>1$}", x_str, elt_width) + } + })?; + + if n > maxprint { + write!(f, "\n[ omitting {} entries ]", n - maxprint)?; + } + } else { + let elt_width = element_width( + self.pairs_ref() + .iter() + .map(|x| std::cmp::max(format!("{:}", x.0).len(), format!("{:?}", x.1).len())), + ); + let mut values_ref = self.values_ref(); + let mut names_ref = self + .names_ref() + .expect("already checked existence of names"); + + let mut values_strs = values_ref.iter().map(|x| format!("{:?}", x)); + let mut names_strs = names_ref.iter().map(|x| format!("{:}", x)); + + let mut col = 0; + + // hard coded max print & console width + // we print at most 20 rows + let elts_per_line = 80 / (elt_width + 1); + + 'lines: for _ in 1..=20 { + for _ in 1..=elts_per_line { + if let Some(name) = names_strs.next() { + write!(f, "{:}{:>2$}", name, " ", elt_width - name.len())?; + } else { + break; + } + } + write!(f, "\n")?; + for _ in 1..=elts_per_line { + if let Some(value) = values_strs.next() { + write!(f, "{:}{:>2$}", value, " ", elt_width - value.len())?; + } else { + break 'lines; + } + } + write!(f, "\n")?; + } + + // for name in names_strs {} + + // let elts_per_line = x_strs + // .take(maxprint) + // .enumerate() + // .try_for_each(|(i, x_str)| { + // if i == 0 { + // col = gutterlen + elt_width; + // write!( + // f, + // "{:>3$}[{}] {:>4$}", + // "", + // i + 1, + // x_str, + // nlen - 1, + // elt_width + // ) + // } else if col + 1 + elt_width > 80 { + // col = gutterlen + elt_width; + // let i_str = format!("{}", i + 1); + // let gutter = nlen - i_str.len(); + // write!( + // f, + // "\n{:>3$}[{}] {:>4$}", + // "", i_str, x_str, gutter, elt_width + // ) + // } else { + // col += 1 + elt_width; + // write!(f, " {:>1$}", x_str, elt_width) + // } + // })?; + + // if n > maxprint { + // write!(f, "\n[ omitting {} entries ]", n - maxprint)?; + // } + } Ok(()) } } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index b82940d7..b852a74c 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -135,41 +135,17 @@ impl RepType { let mut iter = self_subset.iter_subset_indices(); if let Some(i) = iter.next() { - // iter.next() - // .ok_or(Error::Other("subset is not of length 1".to_string()))?; + if let Some(_) = iter.next() { + return Err(Error::Other("subset is not of length 1".to_string())); + } // TODO: subsetting with NA should not be possible. let i = i.unwrap(); - dbg!(i); Ok(self.with_inner_mut(|values| values[i].view_mut())) } else { Err(Error::Other("subset is empty".to_string())) } - - // if let Some(naming) = maybe_naming { - // let mut iter = subsets.bind_names(naming.map).into_iter(); - - // // Here, the subset must produce exactly one index, i.e. we call next() twice and the second - // // yielded element must be None - // if let Some((i, _)) = iter.next() { - // if let None = iter.next() { - // values.with_inner_mut(|v| { - // v.get_mut(i) - // .map_or(Err(Error::Other("todo".to_string())), |x| { - // Ok(x.view_mut()) - // }) - // }) - // } else { - // Err(Error::Other("todo".to_string())) - // } - // } else { - // Err(Error::Other("todo".to_string())) - // } - // } else { - // // TODO - // Err(Error::Other("todo".to_string())) - // } } } } @@ -191,6 +167,39 @@ where } } +pub struct RepTypeIntoIterableNames { + names: Rc>, + na_name: Character, + iter: Box>>, +} + +pub struct RepTypeIterableNames<'a> { + names: &'a [Character], + na_name: &'a Character, + iter: &'a mut Box>>, +} + +impl RepTypeIntoIterableNames { + pub fn iter(&mut self) -> RepTypeIterableNames<'_> { + let names = &self.names[..]; + RepTypeIterableNames { + names, + na_name: &self.na_name, + iter: &mut self.iter, + } + } +} + +impl<'a> Iterator for RepTypeIterableNames<'a> { + type Item = &'a Character; + + fn next(&mut self) -> Option { + // FIXME: This panics when subsetting with NA + let i = self.iter.next()?.unwrap(); + Some(&self.names[i]) + } +} + pub struct RepTypeIntoIterableValues { values: Rc>, na_value: T, @@ -324,6 +333,20 @@ impl RepType { } } +pub struct RepTypeIterNames { + names: Rc>, + iter: Box>>, +} + +impl Iterator for RepTypeIterNames { + type Item = Character; + fn next(&mut self) -> Option { + // FIXME: Already assumes no indexing with NA + let i = self.iter.next()?.unwrap(); + Some(self.names[i].clone()) + } +} + pub struct RepTypeIterPairs { values: Rc>, names: Option>>, @@ -413,6 +436,22 @@ impl RepType { } } + pub fn names_ref(&self) -> Option { + match self.clone() { + RepType::Subset(.., naming) => { + let iter = Box::new(self.iter_subset_indices()); + let naming = naming?; + let names = naming.names.inner_rc(); + + Some(RepTypeIntoIterableNames { + names, + na_name: Character::default(), + iter, + }) + } + } + } + pub fn pairs_ref(&self) -> RepTypeIntoIterable { match self.clone() { RepType::Subset(values, _, maybe_naming) => { @@ -431,8 +470,16 @@ impl RepType { } } - pub fn ensure_named(&self) { - todo!() + // FIXME: Do we really need iter_named and iter_pairs? + pub fn iter_names(&self) -> Option { + match self.clone() { + RepType::Subset(.., maybe_naming) => { + let iter = Box::new(self.iter_subset_indices()); + let names = maybe_naming.map(|x| x.names.inner_rc())?; + + Some(RepTypeIterNames { names, iter }) + } + } } /// Iterates over owned (name, value) tuples. diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index a5a2558b..00ec8258 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -195,42 +195,6 @@ impl TryFrom for Subset { let err = Error::Other("Cannot use object for indexing".to_string()); match value { Obj::Vector(v) => Subset::try_from(v), - // Obj::Vector(v) => match v { - // Vector::Double(_) => { - // if let Vector::Integer(x) = v.as_integer() { - // let x = Obj::Vector(x.into()); - // Subset::try_from(x) - // // todo!() - // // v.try_from() - // // // FIXME: This needs to -1 - // // let indices: Vec = x - // // .values() - // // .inner_rc() - // // .into_iter() - // // .map(|i| i.map(|i| OptionNA::Some(i - 1))) - // // .collect(); - - // // todo!() - // // // Ok(Subset::Indices(indices.into())) - // } else { - // unreachable!() - // } - // } - // Vector::Integer(x) => { - // let indices: Vec = x - // .pairs() - // .iter() - // .map(|(_, x)| x.clone().map(|i| i - 1)) - // .collect(); - // Subset::Indices(x.values()) - - // todo!() - - // // Ok(Subset::Indices(x.values())), - // } - // Vector::Character(x) => Ok(Subset::Names(x.values())), - // Vector::Logical(x) => Ok(Subset::Mask(x.values())), - // }, _ => err.into(), } } diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index 9fd9fb06..a44c044d 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -32,6 +32,42 @@ impl AtomicMode for Character { } } +impl From> for OptionNA { + fn from(value: Option) -> Self { + match value { + None => Self::NA, + Some(x) => Self::Some(x), + } + } +} + +impl From> for OptionNA { + fn from(value: Option) -> Self { + match value { + None => Self::NA, + Some(x) => Self::Some(x), + } + } +} + +impl From> for OptionNA { + fn from(value: Option) -> Self { + match value { + None => Self::NA, + Some(x) => Self::Some(x), + } + } +} + +impl From> for OptionNA { + fn from(value: Option) -> Self { + match value { + None => Self::NA, + Some(x) => Self::Some(x), + } + } +} + impl OptionNA { pub fn is_na(&self) -> bool { matches!(self, OptionNA::NA) @@ -114,6 +150,9 @@ impl TryFrom for Logical { } } +// TODO: Because From> for Obj is implement this means that +// when converting Character -> Obj we get a character vector. +// Change this once we have scalars. impl From for Vector { fn from(value: Character) -> Self { Vector::Character(vec![value].into()) From 9732b6f096adaeeb82bd3b54db95a6a0bea67700 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 15:18:18 +0200 Subject: [PATCH 32/49] ... --- src/callable/primitive/c.rs | 86 ++++++++++++++++---------------- src/callable/primitive/length.rs | 9 +++- src/callable/primitive/mod.rs | 2 - src/object/vector/core.rs | 4 +- src/object/vector/rep.rs | 11 ++-- src/object/vector/reptype.rs | 81 ++++++++---------------------- 6 files changed, 80 insertions(+), 113 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index 792fde85..d1fd30a4 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -160,53 +160,53 @@ impl Callable for PrimitiveC { }); // consume values and merge into a new collection - let v = - match ret { - Vector::Character(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { - match i.clone().as_character() { - Ok(Obj::Vector(Vector::Character(v))) => v.into_iter_values(), - _ => unreachable!(), - } - })) - .collect::>(), - ), - Vector::Double(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.pairs_ref().iter().flat_map( - |(_, i)| match i.clone().as_double() { + let v = match ret { + Vector::Character(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain(vals.iter_values().flat_map(|i| match i.as_character() { + Ok(Obj::Vector(Vector::Character(v))) => v.into_iter_values(), + _ => unreachable!(), + })) + .collect::>(), + ), + Vector::Double(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain( + vals.iter_values() + .flat_map(|i| match i.clone().as_double() { Ok(Obj::Vector(Vector::Double(v))) => v.into_iter_values(), _ => unreachable!(), - }, - )) - .collect::>(), - ), - Vector::Integer(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { - match i.clone().as_integer() { + }), + ) + .collect::>(), + ), + Vector::Integer(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain( + vals.iter_values() + .flat_map(|i| match i.clone().as_integer() { Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter_values(), _ => unreachable!(), - } - })) - .collect::>(), - ), - Vector::Logical(_) => Vector::from( - Vec::>::new() - .into_iter() - .chain(vals.pairs_ref().iter().flat_map(|(_, i)| { - match i.clone().as_logical() { + }), + ) + .collect::>(), + ), + Vector::Logical(_) => Vector::from( + Vec::>::new() + .into_iter() + .chain( + vals.iter_values() + .flat_map(|i| match i.clone().as_logical() { Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter_values(), _ => unreachable!(), - } - })) - .collect::>(), - ), - }; + }), + ) + .collect::>(), + ), + }; if let Some(names) = names { v.set_names(names.into()) @@ -227,14 +227,14 @@ mod tests { fn list_list() { r_expect! {{" l = c(list(1), list(2)) - l[[1]] == 1 & l[[2]] == 2 + l[[1]] == 1 & l[[2]] == 2 && length(l) == 2 "}} } #[test] fn list_vec() { r_expect! {{" l = c(list(1), 2:3) - l[[1]] == 1 & l[[2]][1] == 2 & l[[2]][2] == 3 + length(l) == 2 "}} } #[test] diff --git a/src/callable/primitive/length.rs b/src/callable/primitive/length.rs index d6e539c6..96e63363 100644 --- a/src/callable/primitive/length.rs +++ b/src/callable/primitive/length.rs @@ -47,7 +47,7 @@ impl Callable for PrimitiveLength { Vector::Logical(rep) => rep.len(), Vector::Character(rep) => rep.len(), }, - Obj::List(_) => todo!("Not implemented yet"), + Obj::List(rep) => rep.len(), Obj::Environment(env) => env.len(), _ => return Error::Other("Argument 'x' does not have a length".into()).into(), }; @@ -110,4 +110,11 @@ mod tests { EvalResult::Err(Error::Other("Argument 'x' does not have a length".to_string()).into()) ) } + + #[test] + fn list() { + r_expect! {{" + length(list(1)) == 1 && length(list()) == 0 + "}} + } } diff --git a/src/callable/primitive/mod.rs b/src/callable/primitive/mod.rs index 139373d2..3e698957 100644 --- a/src/callable/primitive/mod.rs +++ b/src/callable/primitive/mod.rs @@ -32,5 +32,3 @@ mod length; pub use length::PrimitiveLength; mod is_null; pub use is_null::PrimitiveIsNull; -mod capture_output; -pub use capture_output::PrimitiveCaptureOutput; diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 66e556b6..4641884a 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -9,7 +9,7 @@ use crate::object::Obj; use super::coercion::CoercibleInto; use super::rep::Rep; use super::reptype::RepType; -use super::reptype::RepTypeIterNames; +use super::reptype::RepTypeIter; use super::subset::Subset; use super::types::*; @@ -107,7 +107,7 @@ impl Vector { } /// Iterate over the names of the vector. - pub fn iter_names(&self) -> Option { + pub fn iter_names(&self) -> Option> { use Vector::*; match self { Double(x) => x.iter_names(), diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index a07e9b5c..63244c46 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -4,7 +4,7 @@ use std::iter::repeat; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::{Naming, RepType, RepTypeIterNames}; +use super::reptype::{Naming, RepType, RepTypeIter}; use super::reptype::{RepTypeIntoIterable, RepTypeIntoIterableNames, RepTypeIntoIterableValues}; use super::subset::Subset; use super::types::*; @@ -84,13 +84,12 @@ where } /// Iterate over the (owned) values of the vector. - // pub fn iter_values(&self) -> Box + '_> { - // let x = self.0.borrow().clone(); - // x.into_iter() - // } + pub fn iter_values(&self) -> RepTypeIter { + self.0.borrow().iter_values() + } /// Iterate over the names of the vector (if they exist). - pub fn iter_names(&self) -> Option { + pub fn iter_names(&self) -> Option> { self.0.borrow().iter_names() } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index b852a74c..c6cbb254 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -151,22 +151,6 @@ impl RepType { } } -// TODO: Remove this it is stupid -impl IntoIterator for RepType -where - T: Clone + Default, -{ - type Item = T; - type IntoIter = RepTypeIter; - fn into_iter(self) -> Self::IntoIter { - // FIXME: this might materialize - let n = self.len(); - match self { - RepType::Subset(..) => RepTypeIter::SubsetIter(self, 0, n), - } - } -} - pub struct RepTypeIntoIterableNames { names: Rc>, na_name: Character, @@ -283,29 +267,6 @@ impl<'a, T: Clone> Iterator for RepTypeIterableValues<'a, T> { } } -// FIXME: Don't make this an enum but simply different structs for eah reptype. -// We yield Box anyway. -pub enum RepTypeIter { - SubsetIter(RepType, usize, usize), -} - -impl Iterator for RepTypeIter { - type Item = T; - fn next(&mut self) -> Option { - match self { - RepTypeIter::SubsetIter(rep, i, len) => { - if i < len { - let x = rep.get_inner(*i); - *i += 1; - x - } else { - None - } - } - } - } -} - impl ViewMut for RepType { fn view_mut(&self) -> Self { match self { @@ -333,17 +294,17 @@ impl RepType { } } -pub struct RepTypeIterNames { - names: Rc>, +pub struct RepTypeIter { + values: Rc>, iter: Box>>, } -impl Iterator for RepTypeIterNames { - type Item = Character; +impl Iterator for RepTypeIter { + type Item = T; fn next(&mut self) -> Option { // FIXME: Already assumes no indexing with NA let i = self.iter.next()?.unwrap(); - Some(self.names[i].clone()) + Some(self.values[i].clone()) } } @@ -470,14 +431,29 @@ impl RepType { } } + pub fn iter_values(&self) -> RepTypeIter { + match self.clone() { + RepType::Subset(values, ..) => { + let iter = Box::new(self.iter_subset_indices()); + RepTypeIter { + values: values.inner_rc(), + iter, + } + } + } + } + // FIXME: Do we really need iter_named and iter_pairs? - pub fn iter_names(&self) -> Option { + pub fn iter_names(&self) -> Option> { match self.clone() { RepType::Subset(.., maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); let names = maybe_naming.map(|x| x.names.inner_rc())?; - Some(RepTypeIterNames { names, iter }) + Some(RepTypeIter { + values: names, + iter, + }) } } } @@ -1460,17 +1436,4 @@ mod test { assert!(z.is_same_type_as(&expected_type)); assert!(z.is_logical()); } - - #[test] - fn iter() { - let x = RepType::from(vec![Some(1), Some(2)]); - let mut xi = x.into_iter(); - assert_eq!(xi.next(), Option::Some(OptionNA::Some(1))); - assert_eq!(xi.next(), Option::Some(OptionNA::Some(2))); - assert_eq!(xi.next(), Option::None); - let xs = RepType::from(vec![Some("a".to_string())]); - let mut xsi = xs.into_iter(); - assert_eq!(xsi.next(), Option::Some(OptionNA::Some("a".to_string()))); - assert_eq!(xsi.next(), Option::None); - } } From 40daa220c1e960b7883293023e53e775f9ebb730 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 15:41:22 +0200 Subject: [PATCH 33/49] ... --- src/callable/primitive/c.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index d1fd30a4..349379bb 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -62,6 +62,7 @@ impl Callable for PrimitiveC { .fold(0, std::cmp::max); // if the output will have names + // either an argument is named or its values has names let named = vals.pairs_ref().iter().any(|(n, o)| { if matches!(n, OptionNA::Some(_)) { return true; @@ -79,7 +80,6 @@ impl Callable for PrimitiveC { } // most complex type was List - // FIXME: handle names if ty == 2 { // TODO: We should use size hints here. let list = List::new(); @@ -131,7 +131,7 @@ impl Callable for PrimitiveC { }; x } else { - unimplemented!() + unreachable!("if we are not building a list, all elements are vectors") } }); Some(nms.collect()) @@ -139,10 +139,11 @@ impl Callable for PrimitiveC { None }; + // otherwise, try to collapse vectors into same type let ret = vals - .pairs_ref() + .values_ref() .iter() - .map(|(_, r)| match r { + .map(|r| match r { Obj::Vector(Vector::Logical(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Integer(_)) => Vector::from(Vec::::new()), Obj::Vector(Vector::Double(_)) => Vector::from(Vec::::new()), @@ -227,14 +228,14 @@ mod tests { fn list_list() { r_expect! {{" l = c(list(1), list(2)) - l[[1]] == 1 & l[[2]] == 2 && length(l) == 2 + l[[1]] == 1 & l[[2]] == 2 "}} } #[test] fn list_vec() { r_expect! {{" l = c(list(1), 2:3) - length(l) == 2 + l[[1]] == 1 & l[[2]][1] == 2 & l[[2]][2] == 3 "}} } #[test] From 1b2b1006a458d2b6d8bc7226a1937638197dbb54 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 15:47:44 +0200 Subject: [PATCH 34/49] ... --- src/callable/primitive/is_null.rs | 2 +- src/callable/primitive/names.rs | 9 ++++++++- src/object/vector/rep.rs | 9 ++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/callable/primitive/is_null.rs b/src/callable/primitive/is_null.rs index 696b1756..3fc173b3 100644 --- a/src/callable/primitive/is_null.rs +++ b/src/callable/primitive/is_null.rs @@ -31,7 +31,7 @@ lazy_static! { /// /// ```custom,{class=r-repl} /// is_null(null) -/// is_null(1) +/// is_null(0) /// ``` #[doc(alias = "is_null")] #[builtin(sym = "is_null")] diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index b8e9e721..4eddc960 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -92,7 +92,7 @@ impl Callable for PrimitiveNames { #[cfg(test)] mod test { use crate::error::Error; - use crate::r; + use crate::{r, r_expect}; #[test] fn no_args() { @@ -114,4 +114,11 @@ mod test { r! { c("a", "b", NA, "d") } ) } + #[test] + fn subset() { + r_expect! {{r#" + names([a = 1, b = 2][1]) == "a" + + "#}} + } } diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 63244c46..065b1f64 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -128,8 +128,15 @@ where RepType::Subset(_, s, n) => { if s.is_empty() { n.map(|n| n.clone().names) + } else if let Some(_) = n { + Some( + self.iter_names() + .expect("checked that names exist") + .collect::>() + .into(), + ) } else { - unimplemented!() + None } } } From d9c8a9b4cc646c2093b6597309a3bf9587b58923 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sat, 5 Oct 2024 16:00:32 +0200 Subject: [PATCH 35/49] ... --- src/callable/primitive/names.rs | 1 - src/lang.rs | 28 ---------------------------- 2 files changed, 29 deletions(-) diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 4eddc960..74047d04 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -118,7 +118,6 @@ mod test { fn subset() { r_expect! {{r#" names([a = 1, b = 2][1]) == "a" - "#}} } } diff --git a/src/lang.rs b/src/lang.rs index b62f4c6e..8ae94d2e 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -259,34 +259,6 @@ impl Obj { } } - // use set_subset instead - pub fn set_named(&mut self, name: &str, value: Obj) -> EvalResult { - todo!() - // I feel this is implemented twice - // because we have l[["a"]] = 1 and l$a = 1; - // match self { - // Obj::List(v) => { - // let loc = v - // .iter_pairs() - // .enumerate() - // .find(|(_, (k, _))| *k == Character::Some(name.into())) - // .map(|(i, _)| i); - - // v.with_inner_mut(|vb| match loc { - // Some(i) => vb[i].1 = value.clone(), - // None => vb.push((Some(name.into()), value.clone())), - // }); - - // Ok(value) - // } - // Obj::Environment(e) => { - // e.values.borrow_mut().insert(name.into(), value.clone()); - // Ok(value) - // } - // _ => Ok(Obj::Null), - // } - } - pub fn environment(&self) -> Option> { match self { Obj::Promise(.., e) | Obj::Function(.., e) | Obj::Environment(e) => Some(e.clone()), From 87d17fda2db67ef2762b8ca334855706a7fd18b4 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 14:55:43 +0200 Subject: [PATCH 36/49] cleanup --- src/callable/core.rs | 6 +- src/callable/operators.rs | 26 ++--- src/callable/primitive/is_null.rs | 14 +-- src/callable/primitive/names.rs | 5 +- src/callable/primitive/sum.rs | 5 - src/lang.rs | 62 ++++++++---- src/object/environment.rs | 15 +++ src/object/vector/core.rs | 3 +- src/object/vector/rep.rs | 60 +++--------- src/object/vector/reptype.rs | 155 ++++++++---------------------- src/object/vector/subsets.rs | 66 ------------- src/object/vector/types.rs | 24 ++--- 12 files changed, 138 insertions(+), 303 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index cbb82220..2db08a02 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -3,7 +3,6 @@ extern crate r_derive; use crate::callable::dyncompare::*; use crate::cli::Experiment; use crate::context::Context; -use crate::error::Error; use crate::object::types::Character; use crate::object::types::Integer; use crate::object::List; @@ -264,10 +263,7 @@ where impl CallableFormals for String {} impl Builtin for String {} -pub fn force_promises( - vals: List, - stack: &mut CallStack, -) -> Result, Obj)>, Signal> { +pub fn force_promises(vals: List, stack: &mut CallStack) -> Result, Signal> { // Force any closures that were created during call. This helps with using // variables as argument for sep and collapse parameters. vals.iter_pairs() diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 95b1ee32..9cf285a0 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -5,7 +5,7 @@ use crate::context::Context; use crate::error::Error; use crate::lang::{CallStack, EvalResult}; use crate::object::types::*; -use crate::{internal_err, object::*}; +use crate::object::*; #[derive(Debug, Clone, PartialEq)] #[builtin(sym = "<-", kind = Infix)] @@ -359,13 +359,10 @@ impl Callable for InfixDollar { unreachable!(); }; - let what = stack.eval(what)?; + let mut what = stack.eval(what)?; match index { - Expr::String(s) | Expr::Symbol(s) => { - let index = Obj::Vector(Vector::Character(vec![Character::Some(s)].into())); - what.try_get_inner(index) - } + Expr::String(s) | Expr::Symbol(s) => what.try_get_named(&s), _ => Ok(Obj::Null), } } @@ -381,13 +378,10 @@ impl Callable for InfixDollar { unreachable!(); }; - let what = stack.eval_mut(what)?; + let mut what = stack.eval_mut(what)?; match index { - Expr::String(s) | Expr::Symbol(s) => { - let index = Obj::Vector(Vector::Character(vec![Character::Some(s)].into())); - what.try_get_inner_mut(index) - } + Expr::String(s) | Expr::Symbol(s) => Ok(what.try_get_named_mut(s.as_str())?), _ => Ok(Obj::Null), } } @@ -404,16 +398,10 @@ impl Callable for InfixDollar { }; let value = stack.eval(value)?; - let what = stack.eval_mut(what)?; + let mut what = stack.eval_mut(what)?; match name { - Expr::String(s) | Expr::Symbol(s) => { - let index = Subset::Names(vec![Character::Some(s)].into()); - Ok(match what { - Obj::List(mut v) => v.set_subset(index, value)?, - _ => unimplemented!(), - }) - } + Expr::String(s) | Expr::Symbol(s) => what.try_set_named(&s, value), _ => unimplemented!(), } } diff --git a/src/callable/primitive/is_null.rs b/src/callable/primitive/is_null.rs index 3fc173b3..8464d62a 100644 --- a/src/callable/primitive/is_null.rs +++ b/src/callable/primitive/is_null.rs @@ -1,16 +1,11 @@ -use lazy_static::lazy_static; use r_derive::*; use crate::callable::core::*; +use crate::formals; use crate::lang::*; use crate::object::types::Logical; use crate::object::*; -lazy_static! { - pub static ref FORMALS: ExprList = - ExprList::from(vec![(Some("x".to_string()), Expr::Missing),]); -} - /// Is an object `null` /// /// Checks whether an object is null @@ -37,11 +32,10 @@ lazy_static! { #[builtin(sym = "is_null")] #[derive(Debug, Clone, PartialEq)] pub struct PrimitiveIsNull; -impl Callable for PrimitiveIsNull { - fn formals(&self) -> ExprList { - FORMALS.clone() - } +formals!(PrimitiveIsNull, "(x)"); + +impl Callable for PrimitiveIsNull { fn call(&self, args: ExprList, stack: &mut CallStack) -> EvalResult { let (args, _ellipsis) = self.match_arg_exprs(args, stack)?; let mut args = Obj::List(args); diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 37c2c803..00208a6a 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -96,10 +96,7 @@ mod test { #[test] fn no_args() { - assert_eq!( - r! { names() }, - Error::ArgumentMissing(String::from("x")).into() - ) + assert_eq!(r! { names() }, Error::Missing.into()) } #[test] diff --git a/src/callable/primitive/sum.rs b/src/callable/primitive/sum.rs index fc08de8d..52470cb7 100644 --- a/src/callable/primitive/sum.rs +++ b/src/callable/primitive/sum.rs @@ -1,4 +1,3 @@ -use lazy_static::lazy_static; use r_derive::*; use crate::callable::core::*; @@ -9,10 +8,6 @@ use crate::lang::*; use crate::object::reptype::RepType; use crate::object::*; -lazy_static! { - pub static ref FORMALS: ExprList = ExprList::from(vec![(None, Expr::Ellipsis(None)),]); -} - /// Calculate a Sum of Elements /// /// # In-Language diff --git a/src/lang.rs b/src/lang.rs index b01785f5..fcb9e6e5 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -127,7 +127,6 @@ impl Obj { Vector::Double(r) => { l.assign(r); } - _ => todo!(), }, _ => return Err(err.into()), }; @@ -245,34 +244,55 @@ impl Obj { } } - pub fn get_named(&mut self, name: &str) -> Option { + pub fn environment(&self) -> Option> { match self { - Obj::List(v) => v - .pairs_ref() - .iter() - .find(|(k, _)| *k == &Character::Some(String::from(name))) - .map(|(_, v)| v.clone()), - Obj::Environment(e) => match e.get(String::from(name)) { - Ok(v) => Some(v), - Err(_) => None, - }, + Obj::Promise(.., e) | Obj::Function(.., e) | Obj::Environment(e) => Some(e.clone()), _ => None, } } - pub fn environment(&self) -> Option> { + /// Used for `$`-assignment. + pub fn try_set_named(&mut self, name: &str, value: Obj) -> EvalResult { match self { - Obj::Promise(.., e) | Obj::Function(.., e) | Obj::Environment(e) => Some(e.clone()), - _ => None, + Obj::List(l) => { + let subset = Subset::Names(vec![Character::Some(name.to_string())].into()); + Ok(l.set_subset(subset, value)?) + } + Obj::Environment(e) => { + e.values.borrow_mut().insert(name.into(), value.clone()); + Ok(value) + } + _ => internal_err!(), + } + } + + /// Used for `$`-assignment. + pub fn try_get_named_mut(&mut self, name: &str) -> EvalResult { + match self { + Obj::List(l) => { + let subset = Subset::Names(vec![Character::Some(name.to_string())].into()); + Ok(l.try_get_inner_mut(subset)?) + } + Obj::Environment(e) => match e.get_mut(String::from(name)) { + Ok(v) => Ok(v), + Err(_) => Err(Error::VariableNotFound(name.into()).into()), + }, + _ => internal_err!(), } } + /// Used for `$`-access. pub fn try_get_named(&mut self, name: &str) -> EvalResult { - use Error::{ArgumentMissing, VariableNotFound}; - match self.get_named(name) { - Some(Obj::Promise(_, Expr::Missing, _)) => Err(ArgumentMissing(name.into()).into()), - Some(x) => Ok(x), - None => Err(VariableNotFound(name.into()).into()), + match self { + Obj::List(l) => { + let subset = Subset::Names(vec![Character::Some(name.to_string())].into()); + Ok(l.try_get_inner(subset)?) + } + Obj::Environment(e) => match e.get(String::from(name)) { + Ok(v) => Ok(v), + Err(_) => Err(Error::VariableNotFound(name.into()).into()), + }, + _ => internal_err!(), } } @@ -290,11 +310,13 @@ impl Obj { } } - // Used for [[ ]] syntax + // Used for `[[`-access. pub fn try_get_inner(&self, index: Obj) -> EvalResult { match self { Obj::Vector(v) => v.try_get(index), Obj::List(l) => EvalResult::Ok(l.try_get_inner(index.try_into()?)?), + // To access environemnts use try_get_named + Obj::Environment(_) => internal_err!(), obj => obj.as_list()?.try_get_inner(index), } } diff --git a/src/object/environment.rs b/src/object/environment.rs index 62e1ab29..735d0403 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -145,3 +145,18 @@ impl Display for Environment { Ok(()) } } + +#[cfg(test)] + +mod tests { + use crate::{r, r_expect}; + + #[test] + fn dollar() { + r_expect! {{" + e = environment() + e$x = 1 + e$x == 1 + "}} + } +} diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 4641884a..03ae1f1d 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -3,6 +3,7 @@ use std::fmt::Display; use crate::error::Error; use crate::lang::EvalResult; +use crate::lang::Signal; use crate::object::CowObj; use crate::object::Obj; @@ -88,7 +89,7 @@ impl Vector { } } - pub fn set_subset(&mut self, subset: Subset, value: Obj) -> Result { + pub fn set_subset(&mut self, subset: Subset, value: Obj) -> Result { use Vector::*; match self { Double(x) => x diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 065b1f64..2fb4fb35 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -1,15 +1,16 @@ use std::cell::{Ref, RefCell, RefMut}; use std::fmt::{Debug, Display}; -use std::iter::repeat; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; use super::reptype::{Naming, RepType, RepTypeIter}; -use super::reptype::{RepTypeIntoIterable, RepTypeIntoIterableNames, RepTypeIntoIterableValues}; +use super::reptype::{ + RepTypeIntoIterableNames, RepTypeIntoIterablePairs, RepTypeIntoIterableValues, +}; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; -use crate::error::Error; +use crate::lang::Signal; use crate::object::reptype::RepTypeIterPairs; use crate::object::Subsets; use crate::object::{CowObj, Obj, ViewMut}; @@ -42,11 +43,11 @@ impl ViewMut for Rep { impl Rep { /// Get the inner value mutably. /// This is used for assignments like `list(1)[[1]] = 10`. - pub fn try_get_inner_mut(&self, subset: Subset) -> Result { + pub fn try_get_inner_mut(&self, subset: Subset) -> Result { self.borrow().try_get_inner_mut(subset) } - pub fn try_get_inner(&self, subset: Subset) -> Result { + pub fn try_get_inner(&self, subset: Subset) -> Result { self.try_get_inner_mut(subset) } } @@ -117,10 +118,7 @@ where } pub fn is_named(&self) -> bool { - match self.borrow().clone() { - RepType::Subset(.., Some(_)) => true, - _ => false, - } + matches!(*self.borrow(), RepType::Subset(.., Some(_))) } pub fn names(&self) -> Option>> { @@ -128,7 +126,7 @@ where RepType::Subset(_, s, n) => { if s.is_empty() { n.map(|n| n.clone().names) - } else if let Some(_) = n { + } else if n.is_some() { Some( self.iter_names() .expect("checked that names exist") @@ -160,31 +158,7 @@ where ))) } - /// Get mutable access to the internal vector through the passed closure. - pub fn with_inner_mut(&self, f: F) -> R - where - F: FnOnce(&mut Vec) -> R, - { - self.0.borrow().with_inner_mut(f) - } - - /// Iterates over owned (name, value) tuples. - pub fn with_pairs(&self, f: F) - where - F: FnMut(Character, T) -> R, - { - self.borrow().with_pairs(f) - } - - /// Iterates over owned (name, value) tuples. - pub fn with_iter_pairs(&self, f: F) -> R - where - F: FnMut(Box>) -> R, - { - todo!() - } - - pub fn pairs_ref(&self) -> RepTypeIntoIterable { + pub fn pairs_ref(&self) -> RepTypeIntoIterablePairs { self.0.borrow().pairs_ref() } @@ -288,7 +262,7 @@ where } } - pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { + pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { self.0.borrow_mut().set_subset(subset, value) } @@ -403,14 +377,6 @@ where self.as_mode::() } - pub fn try_scalar(&self) -> Result { - if self.len() == 1 { - Ok(self.values_ref().iter().next().cloned().unwrap()) - } else { - Err(Error::Other("Vector is not of length 1".to_string())) - } - } - /// Apply over the vector contents to produce a vector of [std::cmp::Ordering] /// /// This function is used primarily in support of the implementation of @@ -655,8 +621,6 @@ where let mut values_strs = values_ref.iter().map(|x| format!("{:?}", x)); let mut names_strs = names_ref.iter().map(|x| format!("{:}", x)); - let mut col = 0; - // hard coded max print & console width // we print at most 20 rows let elts_per_line = 80 / (elt_width + 1); @@ -669,7 +633,7 @@ where break; } } - write!(f, "\n")?; + writeln!(f)?; for _ in 1..=elts_per_line { if let Some(value) = values_strs.next() { write!(f, "{:}{:>2$}", value, " ", elt_width - value.len())?; @@ -677,7 +641,7 @@ where break 'lines; } } - write!(f, "\n")?; + writeln!(f)?; } // for name in names_strs {} diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index c6cbb254..900ff940 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -7,6 +7,7 @@ use super::subsets::Subsets; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::error::Error; +use crate::lang::Signal; use crate::object::{CowObj, ViewMut}; use hashbrown::HashMap; use std::cell::RefCell; @@ -86,7 +87,7 @@ impl From>> for Naming { fn from(value: CowObj>) -> Self { let mut map: HashMap> = HashMap::new(); - value.iter().enumerate().map(|(i, maybe_name)| { + value.iter().enumerate().for_each(|(i, maybe_name)| { if let OptionNA::Some(name) = maybe_name { let indices = map.entry(name.clone()).or_default(); if !indices.contains(&i) { @@ -95,10 +96,7 @@ impl From>> for Naming { }; }); - Self { - map: map.into(), - names: value, - } + Self { map: map.into(), names: value } } } @@ -128,15 +126,15 @@ impl Default for RepType { impl RepType { /// Retrieve the internal data as a mutable view. - pub fn try_get_inner_mut(&self, subset: Subset) -> Result { + pub fn try_get_inner_mut(&self, subset: Subset) -> Result { let self_subset = self.subset(subset); match self_subset { RepType::Subset(..) => { let mut iter = self_subset.iter_subset_indices(); if let Some(i) = iter.next() { - if let Some(_) = iter.next() { - return Err(Error::Other("subset is not of length 1".to_string())); + if iter.next().is_some() { + return Error::Other("subset is not of length 1".to_string()).into(); } // TODO: subsetting with NA should not be possible. @@ -144,7 +142,7 @@ impl RepType { Ok(self.with_inner_mut(|values| values[i].view_mut())) } else { - Err(Error::Other("subset is empty".to_string())) + Error::Other("subset is empty".to_string()).into() } } } @@ -178,9 +176,11 @@ impl<'a> Iterator for RepTypeIterableNames<'a> { type Item = &'a Character; fn next(&mut self) -> Option { - // FIXME: This panics when subsetting with NA - let i = self.iter.next()?.unwrap(); - Some(&self.names[i]) + if let Some(i) = self.iter.next()? { + Some(&self.names[i]) + } else { + Some(self.na_name) + } } } @@ -202,7 +202,7 @@ impl RepTypeIntoIterableValues { } } -pub struct RepTypeIntoIterable { +pub struct RepTypeIntoIterablePairs { values: Rc>, names: Option>>, na_value: T, @@ -210,13 +210,13 @@ pub struct RepTypeIntoIterable { iter: Box>>, } -impl RepTypeIntoIterable { - pub fn iter(&mut self) -> RepTypeIterable<'_, T> { +impl RepTypeIntoIterablePairs { + pub fn iter(&mut self) -> RepTypeIterablePairs<'_, T> { let values = &self.values[..]; let names = self.names.as_ref().map(|names| &names[..]); - RepTypeIterable { + RepTypeIterablePairs { values, names, na_value: &self.na_value, @@ -232,7 +232,7 @@ pub struct RepTypeIterableValues<'a, T: Clone> { iter: &'a mut Box>>, } -pub struct RepTypeIterable<'a, T: Clone> { +pub struct RepTypeIterablePairs<'a, T: Clone> { values: &'a [T], names: Option<&'a [Character]>, na_value: &'a T, @@ -240,20 +240,19 @@ pub struct RepTypeIterable<'a, T: Clone> { iter: &'a mut Box>>, } -impl<'a, T: Clone> Iterator for RepTypeIterable<'a, T> { +impl<'a, T: Clone> Iterator for RepTypeIterablePairs<'a, T> { type Item = (&'a Character, &'a T); fn next(&mut self) -> Option { - // FIXME: This panics when subsetting with NA - let i = self.iter.next()?.unwrap(); - let value = &self.values[i]; - let name = if let Some(names) = self.names { - &names[i] + if let Some(i) = self.iter.next()? { + if let Some(names) = self.names { + Option::Some((&names[i], &self.values[i])) + } else { + Option::Some((self.na_name, &self.values[i])) + } } else { - self.na_name - }; - - Some((name, value)) + Option::Some((self.na_name, self.na_value)) + } } } @@ -261,9 +260,11 @@ impl<'a, T: Clone> Iterator for RepTypeIterableValues<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { - // FIXME: This panics when subsetting with NA - let i = self.iter.next()?.unwrap(); - Some(&self.values[i]) + if let Some(i) = self.iter.next()? { + Some(&self.values[i]) + } else { + Some(self.na_value) + } } } @@ -284,11 +285,7 @@ impl RepType { let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); - RepTypeIterPairs { - values, - names, - iter, - } + RepTypeIterPairs { values, names, iter } } } } @@ -356,7 +353,7 @@ impl RepType { ) } - pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { + pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { match &self { RepType::Subset(..) => { let err = Error::Other("subset must have length 1".to_string()); @@ -368,11 +365,11 @@ impl RepType { // assumes no indexing with NA (unwrap the option) let i = if let Some(i) = i1 { if iter.next().is_some() { - return Err(err); + return err.into(); } i } else { - return Err(err); + return err.into(); } .unwrap(); @@ -388,11 +385,7 @@ impl RepType { let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); - RepTypeIntoIterableValues { - values, - na_value: T::default(), - iter, - } + RepTypeIntoIterableValues { values, na_value: T::default(), iter } } } } @@ -404,23 +397,19 @@ impl RepType { let naming = naming?; let names = naming.names.inner_rc(); - Some(RepTypeIntoIterableNames { - names, - na_name: Character::default(), - iter, - }) + Some(RepTypeIntoIterableNames { names, na_name: Character::default(), iter }) } } } - pub fn pairs_ref(&self) -> RepTypeIntoIterable { + pub fn pairs_ref(&self) -> RepTypeIntoIterablePairs { match self.clone() { RepType::Subset(values, _, maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); - RepTypeIntoIterable { + RepTypeIntoIterablePairs { values, names, na_value: T::default(), @@ -435,10 +424,7 @@ impl RepType { match self.clone() { RepType::Subset(values, ..) => { let iter = Box::new(self.iter_subset_indices()); - RepTypeIter { - values: values.inner_rc(), - iter, - } + RepTypeIter { values: values.inner_rc(), iter } } } } @@ -450,68 +436,11 @@ impl RepType { let iter = Box::new(self.iter_subset_indices()); let names = maybe_naming.map(|x| x.names.inner_rc())?; - Some(RepTypeIter { - values: names, - iter, - }) + Some(RepTypeIter { values: names, iter }) } } } - /// Iterates over owned (name, value) tuples. - pub fn with_pairs(&self, f: F) - where - F: FnMut(Character, T) -> R, - { - todo!() - } - - /// Iterates over owned (name, value) tuples. - pub fn with_iter_pairs_mut(&self, f: F) - where - F: Fn(&mut Character, &mut T) -> R, - { - todo!() - } - - /// Iterates over name, value pairs - pub fn with_iter_values(&self, f: F) - where - F: Fn(&T) -> R, - { - todo!() - } - - /// Iterates over name, value pairs - pub fn with_iter_values_mut(&self, f: F) - where - F: Fn(&T) -> R, - { - todo!() - } - - /// Iterates over name, value pairs - pub fn with_iter_names(&self, f: F) - where - F: Fn(&Character) -> R, - { - todo!() - } - - pub fn with_iter_ref(&self, f: F) - where - F: FnOnce(&T) -> R, - { - todo!() - } - - pub fn with_iter_ref_mut(&self, f: F) - where - F: FnOnce(&T) -> R, - { - todo!() - } - pub fn push_value(&self, value: T) { self.push_named(Character::NA, value); } @@ -1345,7 +1274,7 @@ where mod test { use super::OptionNA::*; use crate::object::reptype::RepType; - use crate::object::{types::*, OptionNA, VecPartialCmp}; + use crate::object::{types::*, VecPartialCmp}; use crate::utils::SameType; #[test] diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 6b6e76e4..3ece0589 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -242,70 +242,4 @@ mod test { let expect = Vector::from(vec![1, 2, 3, 4, 102, 101, 7, 8, 9, 10]); assert_eq!(x, expect) } - - #[test] - fn iter_named_subsets() { - use crate::object::reptype::Naming; - use crate::object::reptype::RepType; - use crate::object::types::{Character, Integer, Logical}; - use crate::object::CowObj; - use crate::object::{Subset, Subsets}; - use hashbrown::HashMap; - use std::cell::RefCell; - use std::rc::Rc; - - let v = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec![1, 2, 3].into_iter().map(Integer::Some).collect(), - )))); - let n = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec!["a".to_string(), "b".to_string(), "c".to_string()] - .into_iter() - .map(Character::Some) - .collect(), - )))); - let s_names: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec!["a".to_string()] - .into_iter() - .map(Character::Some) - .collect(), - )))); - let s_indices: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec![1, 2].into_iter().map(Integer::Some).collect(), - )))); - let s_logical: CowObj> = CowObj::new(Rc::new(RefCell::new(Rc::new( - vec![true, true, true] - .into_iter() - .map(Logical::Some) - .collect(), - )))); - let mut m1: HashMap> = HashMap::new(); - m1.insert("a".to_string(), vec![0_usize]); - m1.insert("b".to_string(), vec![1_usize]); - m1.insert("c".to_string(), vec![2_usize]); - let m: CowObj>> = - CowObj::new(Rc::new(RefCell::new(Rc::new(m1)))); - let naming = Naming { map: m, names: n }; - let x = RepType::Subset( - v, - Subsets(vec![Subset::Names(s_names)]), - Option::Some(naming), - ); - for i in x.iter_subset_indices().take(3) { - println!("{}", i.unwrap()); - } - // let x: CowObj::from(vec![1, 2, 3]); - // // let x = RepType::Sub - } - - // table: - // -- has_names: true - // - range: currently unused - // - mask: correct - // - names: correct - // - indices: false - // -- has_names: false - // - range: currently unused - // - mask: correct - // - names: unimplemented - // - indices: false } diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index a44c044d..39033fb8 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -83,12 +83,12 @@ impl TryFrom for Double { if let Obj::Vector(Vector::Double(v)) = value { if v.len() == 1 { let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - return Ok(x.into()); + Ok(x) } else { - return err; + err } } else { - return err; + err } } } @@ -102,12 +102,12 @@ impl TryFrom for Integer { if let Obj::Vector(Vector::Integer(v)) = value { if v.len() == 1 { let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - return Ok(x.into()); + Ok(x) } else { - return err; + err } } else { - return err; + err } } } @@ -121,12 +121,12 @@ impl TryFrom for Character { if let Obj::Vector(Vector::Character(v)) = value { if v.len() == 1 { let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - return Ok(x.into()); + Ok(x) } else { - return err; + err } } else { - return err; + err } } } @@ -140,12 +140,12 @@ impl TryFrom for Logical { if let Obj::Vector(Vector::Logical(v)) = value { if v.len() == 1 { let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - return Ok(x.into()); + Ok(x) } else { - return err; + err } } else { - return err; + err } } } From 414839bce8bfb440c4400f1584e57f43ec8e8ef2 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 15:21:46 +0200 Subject: [PATCH 37/49] more cleanup --- src/callable/core.rs | 1 + src/callable/primitive/c.rs | 2 +- src/object/vector/subset.rs | 2 -- src/object/vector/subsets.rs | 1 - src/object/vector/types.rs | 12 ++++-------- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 2db08a02..98e2048f 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -68,6 +68,7 @@ pub trait Callable: CallableFormals { // remove any Ellipsis param, and any trailing unassigned params let remainder = formals.pop_trailing(); + // backfill unnamed args, populating ellipsis with overflow for (key, value) in args.iter_pairs() { match key { // named args go directly to ellipsis, they did not match a formal diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index 1fff3940..5ff55eb7 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -65,7 +65,7 @@ impl Callable for PrimitiveC { .fold(0, std::cmp::max); // if the output will have names - // either an argument is named or its values has names + // either an argument was passed via a name or it has names itself let named = vals.pairs_ref().iter().any(|(n, o)| { if matches!(n, OptionNA::Some(_)) { return true; diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index 00ec8258..cf462b35 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -14,8 +14,6 @@ use crate::object::{CowObj, Obj}; /// #[derive(Debug, Clone, PartialEq)] pub enum Subset { - // This is currently 0-index. - // TODO: I think this should be 1-indexed as pushing integer vectors as a subset otherwise requires an allocation. Indices(CowObj>), Mask(CowObj>), Names(CowObj>), diff --git a/src/object/vector/subsets.rs b/src/object/vector/subsets.rs index 3ece0589..f6983464 100644 --- a/src/object/vector/subsets.rs +++ b/src/object/vector/subsets.rs @@ -147,7 +147,6 @@ impl IntoIterator for Subsets { #[cfg(test)] mod test { - use crate::object::Vector; #[test] diff --git a/src/object/vector/types.rs b/src/object/vector/types.rs index 39033fb8..c8cd9a33 100644 --- a/src/object/vector/types.rs +++ b/src/object/vector/types.rs @@ -82,8 +82,7 @@ impl TryFrom for Double { )); if let Obj::Vector(Vector::Double(v)) = value { if v.len() == 1 { - let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - Ok(x) + Ok(v.iter_values().next().expect("length is one")) } else { err } @@ -101,8 +100,7 @@ impl TryFrom for Integer { )); if let Obj::Vector(Vector::Integer(v)) = value { if v.len() == 1 { - let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - Ok(x) + Ok(v.iter_values().next().expect("length is one")) } else { err } @@ -120,8 +118,7 @@ impl TryFrom for Character { )); if let Obj::Vector(Vector::Character(v)) = value { if v.len() == 1 { - let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - Ok(x) + Ok(v.iter_values().next().expect("length is one")) } else { err } @@ -139,8 +136,7 @@ impl TryFrom for Logical { )); if let Obj::Vector(Vector::Logical(v)) = value { if v.len() == 1 { - let x = v.iter_pairs().map(|(_, x)| x.clone()).next().unwrap(); - Ok(x) + Ok(v.iter_values().next().expect("length is one")) } else { err } From 65df1ce48d461df5d37672c3825f9251db2a693e Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 15:34:01 +0200 Subject: [PATCH 38/49] ... --- src/callable/core.rs | 7 ++----- src/callable/operators.rs | 2 +- src/object/vector/core.rs | 11 ----------- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/callable/core.rs b/src/callable/core.rs index 98e2048f..43334a40 100644 --- a/src/callable/core.rs +++ b/src/callable/core.rs @@ -3,11 +3,8 @@ extern crate r_derive; use crate::callable::dyncompare::*; use crate::cli::Experiment; use crate::context::Context; -use crate::object::types::Character; -use crate::object::types::Integer; -use crate::object::List; -use crate::object::Subset; -use crate::object::{Expr, ExprList, Obj}; +use crate::object::types::{Character, Integer}; +use crate::object::{Expr, ExprList, List, Obj, Subset}; use crate::{internal_err, lang::*}; impl std::fmt::Debug for Box { diff --git a/src/callable/operators.rs b/src/callable/operators.rs index 9cf285a0..c2391207 100644 --- a/src/callable/operators.rs +++ b/src/callable/operators.rs @@ -381,7 +381,7 @@ impl Callable for InfixDollar { let mut what = stack.eval_mut(what)?; match index { - Expr::String(s) | Expr::Symbol(s) => Ok(what.try_get_named_mut(s.as_str())?), + Expr::String(s) | Expr::Symbol(s) => what.try_get_named_mut(s.as_str()), _ => Ok(Obj::Null), } } diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 03ae1f1d..20bbb96e 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -168,17 +168,6 @@ impl Vector { } } - // pub fn try_get_inner_mut(&self, index: Obj) -> EvalResult { - // // This method will be needed when we have scalars - // todo!() - // } - - // pub fn try_get_inner(&self, index: Obj) -> EvalResult { - // // This method will be needed when we have scalars - // #[allow(clippy::map_clone)] - // self.try_get_inner_mut(index).map(|v| v.clone()) - // } - pub fn subset(&self, subset: Subset) -> Self { match self { Vector::Double(x) => x.subset(subset).into(), From 888c1c03fe64aa6e1a5ec29ba400ffb41f8516a5 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 15:44:26 +0200 Subject: [PATCH 39/49] ... --- src/object/vector/core.rs | 4 ++-- src/object/vector/rep.rs | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index 20bbb96e..d8ed4d93 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -78,6 +78,8 @@ impl Clone for Vector { // TODO: Ensure that Vector API does not go beyond Rep unless it is really // necessary. + +/// See [`Rep`] for the documentation on the methods. impl Vector { pub fn get(&self, index: usize) -> Option { use Vector::*; @@ -107,7 +109,6 @@ impl Vector { } } - /// Iterate over the names of the vector. pub fn iter_names(&self) -> Option> { use Vector::*; match self { @@ -128,7 +129,6 @@ impl Vector { } } - /// Get the names of the vector. pub fn names(&self) -> Option>> { use Vector::*; match self { diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 2fb4fb35..1969b978 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -75,15 +75,6 @@ where self.0.borrow_mut() } - pub fn replace(&self, value: Self) { - // if we do - // l = list(new.env()) - // l[[1]] = list(99) - // we need to replace list(1, 2) with list(99) - let x = value.0.into_inner(); - self.0.replace(x); - } - /// Iterate over the (owned) values of the vector. pub fn iter_values(&self) -> RepTypeIter { self.0.borrow().iter_values() @@ -262,6 +253,8 @@ where } } + /// Used for `[[`-assignment. + /// The subset should be a single name or index to which the given value will be assigned. pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { self.0.borrow_mut().set_subset(subset, value) } From 7ee00716cca3d62149f062bbacb112fc1e1f4fdd Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 15:57:37 +0200 Subject: [PATCH 40/49] ... --- src/callable/primitive/names.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index 00208a6a..f545b021 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -70,16 +70,10 @@ impl Callable for PrimitiveNames { }, Expr(..) => Ok(Null), // handle arg lists? Function(..) => Ok(Null), // return formals? - List(x) => { - Ok(x.pairs_ref() - .iter() - .map(|(k, _)| match k { - Character::Some(name) => OptionNA::Some(name.clone()), - OptionNA::NA => OptionNA::NA, // unlike R, unnamed elements are NAs - }) - .collect::>>() - .into()) - } + List(l) => match l.names() { + Some(n) => Ok(Obj::Vector(n.into())), + None => Ok(Null), + }, Environment(e) => { let mut names = e.values.borrow().keys().cloned().collect::>(); names.sort(); @@ -117,4 +111,17 @@ mod test { names([a = 1, b = 2][1]) == "a" "#}} } + + #[test] + fn unnamed_atomic() { + r_expect! {{r#" + is_null(names([1, 2])) + "#}} + } + #[test] + fn named_atomic() { + r_expect! {{r#" + names([a = 1]) == "a" + "#}} + } } From 3428546d59911221eaddc3ae45130fe4853b310a Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 15:58:40 +0200 Subject: [PATCH 41/49] clippy --- src/callable/primitive/names.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/callable/primitive/names.rs b/src/callable/primitive/names.rs index f545b021..d0885b58 100644 --- a/src/callable/primitive/names.rs +++ b/src/callable/primitive/names.rs @@ -3,7 +3,6 @@ use r_derive::*; use crate::callable::core::*; use crate::formals; use crate::lang::*; -use crate::object::types::Character; use crate::object::*; /// Get Names of an Object From cb18662f4179d2238ea45e8690beeb37fe409002 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 16:02:18 +0200 Subject: [PATCH 42/49] cleanup cow --- src/object/cow.rs | 13 ------------- src/object/vector/reptype.rs | 10 ---------- 2 files changed, 23 deletions(-) diff --git a/src/object/cow.rs b/src/object/cow.rs index 45392dec..9001f426 100644 --- a/src/object/cow.rs +++ b/src/object/cow.rs @@ -76,19 +76,6 @@ impl CowObj { f(vals) } - /// Get immutable access to the internal vector. - /// In case more than one reference to the internal data exists, - /// the vector is cloned. - pub fn with_inner(&self, f: F) -> R - where - F: FnOnce(&T) -> R, - { - let CowObj(x) = self; - let x1 = &mut *x.borrow_mut(); - let vals: &T = Rc::make_mut(x1); - f(vals) - } - /// Borrow the internal data immutably. pub fn borrow(&self) -> Ref<'_, Rc> { self.0.borrow() diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 900ff940..90cc8fac 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -570,16 +570,6 @@ impl RepType { } } - /// Get mutable access to the internal vector through the passed closure. - pub fn with_inner(&self, f: F) -> R - where - F: FnOnce(&Vec) -> R, - { - match self { - RepType::Subset(v, ..) => v.with_inner(f), - } - } - /// Subsetting a Vector /// /// Introduce a new subset into the aggregate list of subset indices. From 7bd6524d51ba5f70d22eedb6e89f2df5d164a11b Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 16:05:20 +0200 Subject: [PATCH 43/49] remove comment --- src/lang.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lang.rs b/src/lang.rs index fcb9e6e5..9d34f4c5 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -107,10 +107,6 @@ impl Obj { } Obj::List(mut l) => { match value.clone() { - // what about recycling, is this needed here? - // todo: - // x= list(1, 2) - // x[1:2] = c(10, 11) is vectorized in R. Obj::List(r) => { l.assign(r); } From 9de208095a697cc3fd55192f0899997636c40133 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 16:08:26 +0200 Subject: [PATCH 44/49] typo --- src/lang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang.rs b/src/lang.rs index 9d34f4c5..82607da4 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -311,7 +311,7 @@ impl Obj { match self { Obj::Vector(v) => v.try_get(index), Obj::List(l) => EvalResult::Ok(l.try_get_inner(index.try_into()?)?), - // To access environemnts use try_get_named + // To access environments use try_get_named Obj::Environment(_) => internal_err!(), obj => obj.as_list()?.try_get_inner(index), } From 83fe102e55019ddd4163348407d8840f8be697e6 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 16:12:35 +0200 Subject: [PATCH 45/49] cleanup list --- src/object/list.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/object/list.rs b/src/object/list.rs index 31d708e1..dfc3e5d8 100644 --- a/src/object/list.rs +++ b/src/object/list.rs @@ -24,7 +24,7 @@ mod tests { "}} } #[test] - fn copy_on_write_bracket_names() { + fn copy_on_write_double_bracket_names() { r_expect! {{r#" l1 = (a = 1,) l2 = l1 @@ -33,6 +33,15 @@ mod tests { "#}} } #[test] + fn copy_on_write_single_bracket_names() { + r_expect! {{r#" + l1 = (a = 1,) + l2 = l1 + l1["a"] = 2 + l1$a == 2 & l2$a == 1 + "#}} + } + #[test] fn copy_on_write_slice_names() { r_expect! {{r#" l = (a = 1, b = 2, c = 3) From 8cbb02214ab577f857aaf5120b318266d13624e5 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 6 Oct 2024 17:25:01 +0200 Subject: [PATCH 46/49] add iterator tests --- src/object/vector/rep.rs | 77 +------------ src/object/vector/reptype.rs | 216 +++++++++++++++++++++++++++++++++-- 2 files changed, 212 insertions(+), 81 deletions(-) diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index 1969b978..b0c4341e 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -3,17 +3,15 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; -use super::reptype::{Naming, RepType, RepTypeIter}; use super::reptype::{ - RepTypeIntoIterableNames, RepTypeIntoIterablePairs, RepTypeIntoIterableValues, + Naming, RepType, RepTypeIntoIterableNames, RepTypeIntoIterablePairs, RepTypeIntoIterableValues, + RepTypeIter, RepTypeIterPairs, }; use super::subset::Subset; use super::types::*; use super::{OptionNA, Pow, VecPartialCmp}; use crate::lang::Signal; -use crate::object::reptype::RepTypeIterPairs; -use crate::object::Subsets; -use crate::object::{CowObj, Obj, ViewMut}; +use crate::object::{CowObj, Obj, Subsets, ViewMut}; /// Vector Representation /// @@ -47,6 +45,8 @@ impl Rep { self.borrow().try_get_inner_mut(subset) } + /// Get a cloned version of the inner value. + /// This is used for assignments like `list(1)[[1]]`. pub fn try_get_inner(&self, subset: Subset) -> Result { self.try_get_inner_mut(subset) } @@ -161,37 +161,6 @@ where self.0.borrow().names_ref() } - // pub fn iter_subset_indices(&self) -> Box)>> { - // todo!() - // } - - // /// Iterate over mutable references to the values of the vector by passing a closure. - // /// The current subsets of the vector are represented. - // /// This method should be used for vectorized assignment. - // /// - // /// It is - // /// Due to the complex structure of this struct it is not possible to return an iterator that yields - // /// mutable references to the values of the struct. - // pub fn with_iter_pairs_mut_ref<'a, F, R>(&'a self, f: F) -> R - // where - // F: FnMut(&mut [T], Option<&mut [Character]>, Box>>) -> R, - // { - // // We cannot easily get an Iterator that yields &mut T, even through a closure. - // // This is because we might iterate over the same value multiple times (consider a subset x[c(1, 1)]) - // // two consecutive calls to .next() might yield the same mutable reference which is illegal. - // // Instead we give acces to &mut [T] and &mut [Character] and the index iterator - // // - // // Maybe this is possible somehow but I am not sure how to satisfy the rust compiler. - - // when we cannot ensure that each index - // for x in self.iter_mut() {} - // // FIXME: This is impossible I think. - // // It would be possible to pass a closure that receives |&mut T| - // // FIXME: I don't think this would be - // let iter = todo!(); - // f(iter) - // } - pub fn materialize(&self) -> Self { self.borrow().materialize().into() } @@ -636,42 +605,6 @@ where } writeln!(f)?; } - - // for name in names_strs {} - - // let elts_per_line = x_strs - // .take(maxprint) - // .enumerate() - // .try_for_each(|(i, x_str)| { - // if i == 0 { - // col = gutterlen + elt_width; - // write!( - // f, - // "{:>3$}[{}] {:>4$}", - // "", - // i + 1, - // x_str, - // nlen - 1, - // elt_width - // ) - // } else if col + 1 + elt_width > 80 { - // col = gutterlen + elt_width; - // let i_str = format!("{}", i + 1); - // let gutter = nlen - i_str.len(); - // write!( - // f, - // "\n{:>3$}[{}] {:>4$}", - // "", i_str, x_str, gutter, elt_width - // ) - // } else { - // col += 1 + elt_width; - // write!(f, " {:>1$}", x_str, elt_width) - // } - // })?; - - // if n > maxprint { - // write!(f, "\n[ omitting {} entries ]", n - maxprint)?; - // } } Ok(()) } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 90cc8fac..fcad018e 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -56,7 +56,7 @@ impl Naming { }; } - /// Get mutable access to the internal vector through the passed closure. + /// Get mutable access to the internal data via the passed closure. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut HashMap>, &mut Vec>) -> R, @@ -112,8 +112,7 @@ pub enum RepType { impl Clone for RepType { fn clone(&self) -> Self { match self { - // FIXME: should this reall call .view_mut()? should add comment - RepType::Subset(v, s, n) => RepType::Subset(v.view_mut(), s.clone(), n.clone()), + RepType::Subset(v, s, n) => RepType::Subset(v.clone(), s.clone(), n.clone()), } } } @@ -126,15 +125,16 @@ impl Default for RepType { impl RepType { /// Retrieve the internal data as a mutable view. + /// This is important for lists for things like `l$a[1:2] = c(10, 11)` pub fn try_get_inner_mut(&self, subset: Subset) -> Result { - let self_subset = self.subset(subset); - match self_subset { + let new_subset = self.subset(subset); + match new_subset { RepType::Subset(..) => { - let mut iter = self_subset.iter_subset_indices(); + let mut iter = new_subset.iter_subset_indices(); if let Some(i) = iter.next() { if iter.next().is_some() { - return Error::Other("subset is not of length 1".to_string()).into(); + return Error::Other("subset has length > 1".to_string()).into(); } // TODO: subsetting with NA should not be possible. @@ -429,7 +429,6 @@ impl RepType { } } - // FIXME: Do we really need iter_named and iter_pairs? pub fn iter_names(&self) -> Option> { match self.clone() { RepType::Subset(.., maybe_naming) => { @@ -1264,7 +1263,8 @@ where mod test { use super::OptionNA::*; use crate::object::reptype::RepType; - use crate::object::{types::*, VecPartialCmp}; + use crate::object::{types::*, OptionNA, VecPartialCmp}; + use crate::r; use crate::utils::SameType; #[test] @@ -1355,4 +1355,202 @@ mod test { assert!(z.is_same_type_as(&expected_type)); assert!(z.is_logical()); } + + #[test] + fn test_iter_values() { + // Create values as Vec + let values = vec![1, 2, 3, 4, 5]; + + // Create RepType from values + let rep = RepType::from(values.clone()); + + // Use iter_values to get an iterator and collect values + let collected_values: Vec = rep.iter_values().collect(); + + // Expected values as Vec> + let expected_values: Vec = values.into_iter().map(OptionNA::Some).collect(); + + // Assert collected values match expected values + assert_eq!(collected_values, expected_values); + } + + #[test] + fn test_iter_names() { + // Create values with names + let values_with_names = vec![ + (Character::Some(String::from("a")), 1), + (Character::Some(String::from("b")), 2), + (Character::NA, 3), + (Character::Some(String::from("d")), 4), + (Character::NA, 5), + ]; + + // Create RepType from values with names + let rep = RepType::from(values_with_names.clone()); + + // Use iter_names to get an iterator + let names_iter = rep.iter_names(); + + // Ensure iter_names is Some iterator + assert!(names_iter.is_some()); + + // Collect names + let collected_names: Vec = names_iter.unwrap().collect(); + + // Expected names + let expected_names: Vec = values_with_names + .iter() + .map(|(name_opt, _)| match name_opt { + Some(name) => Character::Some(name.clone()), + Character::NA => Character::NA, + }) + .collect(); + + // Assert collected names match expected names + assert_eq!(collected_names, expected_names); + } + + use crate::object::{Obj, Vector}; + // The tests below don't test the subsetting mechanism, which is instead tested in subsets.rs + #[test] + fn iter_pairs_mixed_names() { + let x = r!(c(a = 1, 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().iter_pairs() + } else { + unreachable!() + }; + + assert_eq!( + x.next().unwrap(), + (Character::Some("a".to_string()), Double::Some(1.0)) + ); + assert_eq!(x.next().unwrap(), (Character::NA, Double::Some(2.0))); + assert_eq!(x.next(), None); + } + + #[test] + fn iter_pairs_no_names() { + let x = r!(c(1, 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().iter_pairs() + } else { + unreachable!() + }; + + assert_eq!(x.next().unwrap(), (Character::NA, Double::Some(1.0))); + assert_eq!(x.next().unwrap(), (Character::NA, Double::Some(2.0))); + assert_eq!(x.next(), None); + } + + #[test] + fn iter_values() { + let x = r!(c(1, 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().iter_values() + } else { + unreachable!() + }; + + assert_eq!(x.next().unwrap(), Double::Some(1.0)); + assert_eq!(x.next().unwrap(), Double::Some(2.0)); + assert_eq!(x.next(), None); + } + + #[test] + fn iter_names_none() { + let x = r!(c(1, 2)).unwrap(); + + let x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().iter_names() + } else { + unreachable!() + }; + + assert!(x.is_none()) + } + + #[test] + fn iter_names_some() { + let x = r!(c(1, b = 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().iter_names().unwrap() + } else { + unreachable!() + }; + + assert_eq!(x.next().unwrap(), Character::NA); + assert_eq!(x.next().unwrap(), Character::Some("b".to_string())); + assert_eq!(x.next(), None); + } + + #[test] + fn names_ref_iter_some() { + let x = r!(c(1, b = 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().names_ref().unwrap() + } else { + unreachable!() + }; + + let mut x = x.iter(); + + assert_eq!(x.next().unwrap(), &Character::NA); + assert_eq!(x.next().unwrap(), &Character::Some("b".to_string())); + assert_eq!(x.next(), None); + } + + #[test] + #[should_panic] + fn names_ref_iter_none() { + let x = r!(c(1, 2)).unwrap(); + + if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().names_ref().unwrap() + } else { + unreachable!() + }; + } + + #[test] + fn values_ref_iter() { + let x = r!(c(1, b = 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().values_ref() + } else { + unreachable!() + }; + + let mut x = x.iter(); + + assert_eq!(x.next().unwrap(), &Double::Some(1.0)); + assert_eq!(x.next().unwrap(), &Double::Some(2.0)); + assert_eq!(x.next(), None); + } + + #[test] + fn pairs_ref_iter() { + let x = r!(c(1, b = 2)).unwrap(); + + let mut x = if let Obj::Vector(Vector::Double(r)) = x { + r.borrow().clone().pairs_ref() + } else { + unreachable!() + }; + + let mut x = x.iter(); + + assert_eq!(x.next().unwrap(), (&Character::NA, &Double::Some(1.0))); + assert_eq!( + x.next().unwrap(), + (&Character::Some("b".to_string()), &Double::Some(2.0)) + ); + assert_eq!(x.next(), None); + } } From 32e6016cab56f113ffc93458bae4f548337d4c1b Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 9 Oct 2024 17:50:18 +0200 Subject: [PATCH 47/49] cleanup rep(type) --- src/callable/primitive/c.rs | 8 +-- src/object/vector/core.rs | 4 +- src/object/vector/rep.rs | 89 ++++++++++-------------- src/object/vector/reptype.rs | 129 ++++++++++++++--------------------- src/object/vector/subset.rs | 2 +- 5 files changed, 93 insertions(+), 139 deletions(-) diff --git a/src/callable/primitive/c.rs b/src/callable/primitive/c.rs index 5ff55eb7..91b57320 100644 --- a/src/callable/primitive/c.rs +++ b/src/callable/primitive/c.rs @@ -169,7 +169,7 @@ impl Callable for PrimitiveC { Vec::>::new() .into_iter() .chain(vals.iter_values().flat_map(|i| match i.as_character() { - Ok(Obj::Vector(Vector::Character(v))) => v.into_iter_values(), + Ok(Obj::Vector(Vector::Character(v))) => v.iter_values(), _ => unreachable!(), })) .collect::>(), @@ -180,7 +180,7 @@ impl Callable for PrimitiveC { .chain( vals.iter_values() .flat_map(|i| match i.clone().as_double() { - Ok(Obj::Vector(Vector::Double(v))) => v.into_iter_values(), + Ok(Obj::Vector(Vector::Double(v))) => v.iter_values(), _ => unreachable!(), }), ) @@ -192,7 +192,7 @@ impl Callable for PrimitiveC { .chain( vals.iter_values() .flat_map(|i| match i.clone().as_integer() { - Ok(Obj::Vector(Vector::Integer(v))) => v.into_iter_values(), + Ok(Obj::Vector(Vector::Integer(v))) => v.iter_values(), _ => unreachable!(), }), ) @@ -204,7 +204,7 @@ impl Callable for PrimitiveC { .chain( vals.iter_values() .flat_map(|i| match i.clone().as_logical() { - Ok(Obj::Vector(Vector::Logical(v))) => v.into_iter_values(), + Ok(Obj::Vector(Vector::Logical(v))) => v.iter_values(), _ => unreachable!(), }), ) diff --git a/src/object/vector/core.rs b/src/object/vector/core.rs index d8ed4d93..8784799c 100644 --- a/src/object/vector/core.rs +++ b/src/object/vector/core.rs @@ -9,8 +9,8 @@ use crate::object::Obj; use super::coercion::CoercibleInto; use super::rep::Rep; +use super::reptype::IterableValues; use super::reptype::RepType; -use super::reptype::RepTypeIter; use super::subset::Subset; use super::types::*; @@ -109,7 +109,7 @@ impl Vector { } } - pub fn iter_names(&self) -> Option> { + pub fn iter_names(&self) -> Option> { use Vector::*; match self { Double(x) => x.iter_names(), diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index b0c4341e..b2345dc1 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -4,8 +4,8 @@ use std::fmt::{Debug, Display}; use super::coercion::{AtomicMode, CoercibleInto, CommonCmp, CommonNum, MinimallyNumeric}; use super::iterators::{map_common_numeric, zip_recycle}; use super::reptype::{ - Naming, RepType, RepTypeIntoIterableNames, RepTypeIntoIterablePairs, RepTypeIntoIterableValues, - RepTypeIter, RepTypeIterPairs, + IntoIterableRefNames, IntoIterableRefPairs, IntoIterableRefValues, IterablePairs, + IterableValues, Naming, RepType, }; use super::subset::Subset; use super::types::*; @@ -46,21 +46,17 @@ impl Rep { } /// Get a cloned version of the inner value. - /// This is used for assignments like `list(1)[[1]]`. + /// This is used for accessing inner values like `list(1)[[1]]`. pub fn try_get_inner(&self, subset: Subset) -> Result { - self.try_get_inner_mut(subset) + self.try_get_inner_mut(subset).map(|x| x.clone()) } } impl Rep { /// Iterate over the owned names and values of the vector. - pub fn iter_pairs(&self) -> RepTypeIterPairs { - // FIXME: This should maybe return an option + pub fn iter_pairs(&self) -> IterablePairs { self.0.borrow().clone().iter_pairs() } - pub fn into_iter_values(self) -> Box> { - Box::new(self.clone().iter_pairs().map(|(_, x)| x)) - } } impl Rep @@ -76,12 +72,12 @@ where } /// Iterate over the (owned) values of the vector. - pub fn iter_values(&self) -> RepTypeIter { + pub fn iter_values(&self) -> IterableValues { self.0.borrow().iter_values() } /// Iterate over the names of the vector (if they exist). - pub fn iter_names(&self) -> Option> { + pub fn iter_names(&self) -> Option> { self.0.borrow().iter_names() } @@ -93,11 +89,7 @@ where self } - pub fn remove(&self, index: usize) -> (Character, T) { - self.borrow().remove(index) - } - - /// Reindex the mapping from names to indices. + /// Reindex the mapping from names to indices using the names vector from the `Naming`. pub fn reindex(&mut self) { self.borrow_mut().reindex() } @@ -108,10 +100,12 @@ where self.0.replace(new_repr); } + /// Whether the vector representation has names. pub fn is_named(&self) -> bool { matches!(*self.borrow(), RepType::Subset(.., Some(_))) } + /// Return the names of the vector if there are any. pub fn names(&self) -> Option>> { match self.borrow().clone() { RepType::Subset(_, s, n) => { @@ -135,29 +129,43 @@ where self.0.into_inner().dedup_last().into() } - /// Preallocates a - pub fn with_capacity(n: usize, names: bool) -> Self { + /// Constructs a new, empty `Rep` with at least the specified `capacity`. + /// Names are only include if `names` is true. + pub fn with_capacity(capacity: usize, names: bool) -> Self { let naming = if names { - Some(Naming::with_capacity(n)) + Some(Naming::with_capacity(capacity)) } else { None }; Self(RefCell::new(RepType::Subset( - CowObj::from(Vec::with_capacity(n)), + CowObj::from(Vec::with_capacity(capacity)), Subsets::default(), naming, ))) } - pub fn pairs_ref(&self) -> RepTypeIntoIterablePairs { + /// Get an `RepTypeIntoIterablePairs` which in turn can be converted into an iterator over + /// pairs of references (&name, &value). + /// + /// Directly getting an iterator is not possible due to lifetime issues. + pub fn pairs_ref(&self) -> IntoIterableRefPairs { self.0.borrow().pairs_ref() } - pub fn values_ref(&self) -> RepTypeIntoIterableValues { + /// Get an `Option>` which in turn can be converted into an iterator over + /// references to the values. + /// The `None` variant is returned if the `Rep` is not named. + /// + /// Directly getting an iterator is not possible due to lifetime issues. + pub fn values_ref(&self) -> IntoIterableRefValues { self.0.borrow().values_ref() } - pub fn names_ref(&self) -> Option { + /// Get an `RepTypeIntoIterableValues` which in turn can be converted into an iterator over + /// references to the names. + /// + /// Directly getting an iterator is not possible due to lifetime issues. + pub fn names_ref(&self) -> Option { self.0.borrow().names_ref() } @@ -215,19 +223,14 @@ where x.map(|x| x.into()) } - pub fn values(&self) -> CowObj> { - self.materialize_inplace(); - match self.0.borrow().clone() { - RepType::Subset(values, ..) => values, - } - } - - /// Used for `[[`-assignment. - /// The subset should be a single name or index to which the given value will be assigned. + /// Change a value at the location given by `subset` to the provided `value`. + /// If the `subset` does not have length `1`, an error is returned. pub fn set_subset(&mut self, subset: Subset, value: T) -> Result { + // Used for `[[`-assignment. self.0.borrow_mut().set_subset(subset, value) } + /// Push a named `value` with a given `name` onto the `Rep`. pub fn push_named(&self, name: OptionNA, value: T) { self.borrow().push_named(name, value) } @@ -237,9 +240,6 @@ where T: From + Clone, R: Clone + Default, { - // TODO: Handle names here - // The assign method from List had a lot more code, - // check that everything is covered here. self.0.borrow_mut().assign(value.0.into_inner()).into() } /// Test the mode of the internal vector type @@ -379,19 +379,6 @@ where } } -// impl From for Rep -// where -// T: Clone + Default, -// { -// fn from(x: T) -> Self { -// Rep(RefCell::new(RepType::Subset( -// vec![x].into(), -// Subsets::default(), -// None, -// ))) -// } -// } - impl From> for Rep where T: Clone + Default, @@ -519,17 +506,11 @@ where if !self.is_named() { let elt_width = element_width(self.values_ref().iter().map(|x| format!("{:?}", x).len())); - // TODO: iteratively calculate when we hit max print so our - // max_len isn't inflated by a value that is omitted let mut values_ref = self.values_ref(); let x_strs = values_ref.iter().map(|xi| format!("{:?}", xi)); let mut col = 0; - //| [1] 1 2 3 4 5 6 7 8 9| - //|[10] 10 11 12 13 14 15 16 17 18| - //|-----| - // in the above example the gutterlen is 5 let gutterlen = 2 + nlen + 1; // hard coded max print & console width diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index fcad018e..1d38a779 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -21,28 +21,20 @@ pub struct Naming { } impl Naming { + /// Create an empty `Naming` pub fn new() -> Self { Naming::default() } - pub fn with_capacity(n: usize) -> Self { + /// Create a naming with the given `capacity`. + pub fn with_capacity(capacity: usize) -> Self { Self { - map: HashMap::>::with_capacity(n).into(), - names: CowObj::from(Vec::::with_capacity(n)), - } - } - - pub fn remove(&self, index: usize) -> Character { - // FIXME: Already assumes names are unique - let maybe_name = self.names.with_inner_mut(|names| names.remove(index)); - if let OptionNA::Some(name) = maybe_name { - self.map.with_inner_mut(|map| map.remove(&name)); - OptionNA::Some(name) - } else { - OptionNA::NA + map: HashMap::>::with_capacity(capacity).into(), + names: CowObj::from(Vec::::with_capacity(capacity)), } } + /// Push a new name onto the `Naming`. pub fn push_name(&self, name: OptionNA) { self.names.with_inner_mut(|v| v.push(name.clone())); if let OptionNA::Some(name) = name { @@ -56,7 +48,7 @@ impl Naming { }; } - /// Get mutable access to the internal data via the passed closure. + /// Get mutable access to the internal data (map and names vector) via the passed closure. pub fn with_inner_mut(&self, f: F) -> R where F: FnOnce(&mut HashMap>, &mut Vec>) -> R, @@ -149,7 +141,7 @@ impl RepType { } } -pub struct RepTypeIntoIterableNames { +pub struct IntoIterableRefNames { names: Rc>, na_name: Character, iter: Box>>, @@ -161,7 +153,7 @@ pub struct RepTypeIterableNames<'a> { iter: &'a mut Box>>, } -impl RepTypeIntoIterableNames { +impl IntoIterableRefNames { pub fn iter(&mut self) -> RepTypeIterableNames<'_> { let names = &self.names[..]; RepTypeIterableNames { @@ -184,17 +176,17 @@ impl<'a> Iterator for RepTypeIterableNames<'a> { } } -pub struct RepTypeIntoIterableValues { +pub struct IntoIterableRefValues { values: Rc>, na_value: T, iter: Box>>, } -impl RepTypeIntoIterableValues { - pub fn iter(&mut self) -> RepTypeIterableValues<'_, T> { +impl IntoIterableRefValues { + pub fn iter(&mut self) -> IterableRefValues<'_, T> { let values = &self.values[..]; - RepTypeIterableValues { + IterableRefValues { values, na_value: &self.na_value, iter: &mut self.iter, @@ -202,7 +194,7 @@ impl RepTypeIntoIterableValues { } } -pub struct RepTypeIntoIterablePairs { +pub struct IntoIterableRefPairs { values: Rc>, names: Option>>, na_value: T, @@ -210,13 +202,13 @@ pub struct RepTypeIntoIterablePairs { iter: Box>>, } -impl RepTypeIntoIterablePairs { - pub fn iter(&mut self) -> RepTypeIterablePairs<'_, T> { +impl IntoIterableRefPairs { + pub fn iter(&mut self) -> IterableRefPairs<'_, T> { let values = &self.values[..]; let names = self.names.as_ref().map(|names| &names[..]); - RepTypeIterablePairs { + IterableRefPairs { values, names, na_value: &self.na_value, @@ -226,13 +218,13 @@ impl RepTypeIntoIterablePairs { } } -pub struct RepTypeIterableValues<'a, T: Clone> { +pub struct IterableRefValues<'a, T: Clone> { values: &'a [T], na_value: &'a T, iter: &'a mut Box>>, } -pub struct RepTypeIterablePairs<'a, T: Clone> { +pub struct IterableRefPairs<'a, T: Clone> { values: &'a [T], names: Option<&'a [Character]>, na_value: &'a T, @@ -240,7 +232,7 @@ pub struct RepTypeIterablePairs<'a, T: Clone> { iter: &'a mut Box>>, } -impl<'a, T: Clone> Iterator for RepTypeIterablePairs<'a, T> { +impl<'a, T: Clone> Iterator for IterableRefPairs<'a, T> { type Item = (&'a Character, &'a T); fn next(&mut self) -> Option { @@ -256,7 +248,7 @@ impl<'a, T: Clone> Iterator for RepTypeIterablePairs<'a, T> { } } -impl<'a, T: Clone> Iterator for RepTypeIterableValues<'a, T> { +impl<'a, T: Clone> Iterator for IterableRefValues<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { @@ -276,27 +268,12 @@ impl ViewMut for RepType { } } -impl RepType { - // FIXME: Do we really need iter_named and iter_pairs? - pub fn iter_pairs(&self) -> RepTypeIterPairs { - match self.clone() { - RepType::Subset(values, _, maybe_naming) => { - let iter = Box::new(self.iter_subset_indices()); - let values = values.inner_rc(); - let names = maybe_naming.map(|x| x.names.inner_rc()); - - RepTypeIterPairs { values, names, iter } - } - } - } -} - -pub struct RepTypeIter { +pub struct IterableValues { values: Rc>, iter: Box>>, } -impl Iterator for RepTypeIter { +impl Iterator for IterableValues { type Item = T; fn next(&mut self) -> Option { // FIXME: Already assumes no indexing with NA @@ -305,13 +282,13 @@ impl Iterator for RepTypeIter { } } -pub struct RepTypeIterPairs { +pub struct IterablePairs { values: Rc>, names: Option>>, iter: Box>>, } -impl Iterator for RepTypeIterPairs { +impl Iterator for IterablePairs { type Item = (Character, T); fn next(&mut self) -> Option { // FIXME: Already assumes no indexing with NA @@ -379,37 +356,37 @@ impl RepType { } } - pub fn values_ref(&self) -> RepTypeIntoIterableValues { + pub fn values_ref(&self) -> IntoIterableRefValues { match self.clone() { RepType::Subset(values, ..) => { let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); - RepTypeIntoIterableValues { values, na_value: T::default(), iter } + IntoIterableRefValues { values, na_value: T::default(), iter } } } } - pub fn names_ref(&self) -> Option { + pub fn names_ref(&self) -> Option { match self.clone() { RepType::Subset(.., naming) => { let iter = Box::new(self.iter_subset_indices()); let naming = naming?; let names = naming.names.inner_rc(); - Some(RepTypeIntoIterableNames { names, na_name: Character::default(), iter }) + Some(IntoIterableRefNames { names, na_name: Character::default(), iter }) } } } - pub fn pairs_ref(&self) -> RepTypeIntoIterablePairs { + pub fn pairs_ref(&self) -> IntoIterableRefPairs { match self.clone() { RepType::Subset(values, _, maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); let values = values.inner_rc(); let names = maybe_naming.map(|x| x.names.inner_rc()); - RepTypeIntoIterablePairs { + IntoIterableRefPairs { values, names, na_value: T::default(), @@ -420,22 +397,34 @@ impl RepType { } } - pub fn iter_values(&self) -> RepTypeIter { + pub fn iter_pairs(&self) -> IterablePairs { + match self.clone() { + RepType::Subset(values, _, maybe_naming) => { + let iter = Box::new(self.iter_subset_indices()); + let values = values.inner_rc(); + let names = maybe_naming.map(|x| x.names.inner_rc()); + + IterablePairs { values, names, iter } + } + } + } + + pub fn iter_values(&self) -> IterableValues { match self.clone() { RepType::Subset(values, ..) => { let iter = Box::new(self.iter_subset_indices()); - RepTypeIter { values: values.inner_rc(), iter } + IterableValues { values: values.inner_rc(), iter } } } } - pub fn iter_names(&self) -> Option> { + pub fn iter_names(&self) -> Option> { match self.clone() { RepType::Subset(.., maybe_naming) => { let iter = Box::new(self.iter_subset_indices()); let names = maybe_naming.map(|x| x.names.inner_rc())?; - Some(RepTypeIter { values: names, iter }) + Some(IterableValues { values: names, iter }) } } } @@ -444,25 +433,6 @@ impl RepType { self.push_named(Character::NA, value); } - pub fn remove(&self, index: usize) -> (Character, T) { - match self { - RepType::Subset(values, Subsets(subsets), maybe_naming) => { - if subsets.as_slice().is_empty() { - let value = values.with_inner_mut(|values| values.remove(index)); - - let name = if let Some(naming) = maybe_naming { - naming.remove(index) - } else { - OptionNA::NA - }; - (name, value) - } else { - unimplemented!() - } - } - } - } - pub fn push_named(&self, name: OptionNA, value: T) { match self { RepType::Subset(values, Subsets(subsets), maybe_naming) => match subsets.as_slice() { @@ -512,6 +482,7 @@ impl RepType { } pub fn dedup_last(self) -> Self { + println!("dedup"); // TODO(docu): What exactly does this? I think there might still be a bug here because we drain ALL indices (?) match self { RepType::Subset(values, subsets, Some(naming)) => { @@ -534,8 +505,10 @@ impl RepType { } }); + println!("Hi"); for (_, indices) in map.iter_mut() { - indices.drain(0..indices.len()); + indices.drain(0..(indices.len())); + dbg!(&indices); } }); RepType::Subset(values, subsets, Some(naming)) diff --git a/src/object/vector/subset.rs b/src/object/vector/subset.rs index cf462b35..243ba739 100644 --- a/src/object/vector/subset.rs +++ b/src/object/vector/subset.rs @@ -228,7 +228,7 @@ impl TryFrom for Subset { value @ Vector::Double(_) => Subset::try_from(value.as_integer()), Vector::Integer(v) => { let y = v - .into_iter_values() + .iter_values() .map(|i| match i { OptionNA::Some(x) => OptionNA::Some(x - 1), OptionNA::NA => OptionNA::NA, From 059d87d830ed575c9cfe226db5a7227c7afd342e Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 9 Oct 2024 18:01:31 +0200 Subject: [PATCH 48/49] changelog --- src/CHANGELOG.md | 22 ++++++++++++++++++++++ src/callable/primitive/list.rs | 6 +++++- src/object/vector/rep.rs | 1 + src/object/vector/reptype.rs | 4 ---- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 7f2ae52b..447271b1 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -2,6 +2,28 @@ ## Changes +* Named vectors were added and can e.g. be constructed via `[a = 1, b = 2]` +* The `is_null()` primitive was added +* Setting a list value to `null` actually sets it to `null` and does not remove it. + +## Internals + +* The `List` is now represented as a `Rep`, unifying heterogenous and atomic vectors. + This included a considerable refactor. +* Iterating over references of a `Rep` was made much simpler and new methods were added + and unused ones removed. + +## Notable Bugs Addressed + +* Concatenating `list`s now works as expected (#177). +* `names()` now works correctly when the vector is subset, e.g. + `names(list(a = 1, b = 2)[1])` (#181). +* `[[.<-` assignment has been fixed for lists (#179) + +# 0.4.0 + +## Changes + * Added German (`ger`) localization. * Digits can now be separated by an underscore to improve readability. diff --git a/src/callable/primitive/list.rs b/src/callable/primitive/list.rs index 05715e62..24cb79f9 100644 --- a/src/callable/primitive/list.rs +++ b/src/callable/primitive/list.rs @@ -26,6 +26,11 @@ use crate::object::*; /// /// `...`: Arguments to collect into a `list`. /// +/// ## Differences to the R implementation +/// +/// Setting a list value to `null` does not remove the element but +/// sets it to the value `null`. +/// /// ## Examples /// /// ```custom,{class=r-repl} @@ -45,7 +50,6 @@ use crate::object::*; /// ```custom,{class=r-repl} /// (1,) /// ``` -/// #[doc(alias = "list")] #[builtin(sym = "list")] #[derive(Debug, Clone, PartialEq)] diff --git a/src/object/vector/rep.rs b/src/object/vector/rep.rs index b2345dc1..8fec7372 100644 --- a/src/object/vector/rep.rs +++ b/src/object/vector/rep.rs @@ -48,6 +48,7 @@ impl Rep { /// Get a cloned version of the inner value. /// This is used for accessing inner values like `list(1)[[1]]`. pub fn try_get_inner(&self, subset: Subset) -> Result { + #[allow(clippy::map_clone)] self.try_get_inner_mut(subset).map(|x| x.clone()) } } diff --git a/src/object/vector/reptype.rs b/src/object/vector/reptype.rs index 1d38a779..237e6f73 100644 --- a/src/object/vector/reptype.rs +++ b/src/object/vector/reptype.rs @@ -482,8 +482,6 @@ impl RepType { } pub fn dedup_last(self) -> Self { - println!("dedup"); - // TODO(docu): What exactly does this? I think there might still be a bug here because we drain ALL indices (?) match self { RepType::Subset(values, subsets, Some(naming)) => { naming.with_inner_mut(|map, names| { @@ -505,10 +503,8 @@ impl RepType { } }); - println!("Hi"); for (_, indices) in map.iter_mut() { indices.drain(0..(indices.len())); - dbg!(&indices); } }); RepType::Subset(values, subsets, Some(naming)) From 4d82494b034ecf26057bcf6093183f2a80735a92 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Wed, 9 Oct 2024 18:03:59 +0200 Subject: [PATCH 49/49] Update src/CHANGELOG.md --- src/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 447271b1..60deb53e 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -18,7 +18,7 @@ * Concatenating `list`s now works as expected (#177). * `names()` now works correctly when the vector is subset, e.g. `names(list(a = 1, b = 2)[1])` (#181). -* `[[.<-` assignment has been fixed for lists (#179) +* `[[.<-` assignment has been fixed for lists (#179) # 0.4.0