From 782460e472c619cfb0d8a35255a2e7f0a0c33e34 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 29 Nov 2023 16:26:51 +0100 Subject: [PATCH] add get_mut function for lists --- mers_lib/src/data/mod.rs | 24 ++++-- mers_lib/src/lib.rs | 20 ++++- mers_lib/src/program/configs/mod.rs | 18 ++-- mers_lib/src/program/configs/with_list.rs | 100 +++++++++++++++++++--- 4 files changed, 134 insertions(+), 28 deletions(-) diff --git a/mers_lib/src/data/mod.rs b/mers_lib/src/data/mod.rs index 5ab6b1e..e3ed59b 100755 --- a/mers_lib/src/data/mod.rs +++ b/mers_lib/src/data/mod.rs @@ -101,6 +101,9 @@ impl Data { data: Arc::new(RwLock::new(data)), } } + pub fn is_mut(&self) -> bool { + self.is_mut + } pub fn empty_tuple() -> Self { Self::new(tuple::Tuple(vec![])) } @@ -166,20 +169,27 @@ impl Data { } self.get_mut_unchecked() } - pub fn mkref(&self) -> Self { + /// If self is already mut, returns `(Data, false)`. If not, inner data will be cloned and `(Data, true)` will be returned. + pub fn mkref(&self) -> (Self, bool) { if self.is_mut { self.counts .1 .fetch_add(1, std::sync::atomic::Ordering::Relaxed); - Self { - is_mut: true, - counts: Arc::clone(&self.counts), - data: Arc::clone(&self.data), - } + ( + Self { + is_mut: true, + counts: Arc::clone(&self.counts), + data: Arc::clone(&self.data), + }, + false, + ) } else { #[cfg(debug_assertions)] eprintln!("[mers:data:cow] cloning! mkref called on immutable data"); - Self::new_boxed(self.data.read().unwrap().clone(), true) + ( + Self::new_boxed(self.data.read().unwrap().clone(), true), + true, + ) } } } diff --git a/mers_lib/src/lib.rs b/mers_lib/src/lib.rs index 6c98ef4..f327245 100755 --- a/mers_lib/src/lib.rs +++ b/mers_lib/src/lib.rs @@ -22,11 +22,29 @@ pub mod prelude_compile { /// with this, you can add values (usually functions), /// or add your own types to the language: /// +/// use mers_lib::prelude_extend_config::Config; /// fn add_thing(cfg: Config) -> Config { -/// /// use the methods on Config to add things (see the Config source code for examples) +/// // use the methods on Config to add things (see the Config source code for examples) +/// cfg.add_var("my_var".to_owned(), todo!()) /// } /// /// then use the Config when compiling and running your code, and your customizations will be available. pub mod prelude_extend_config { pub use crate::program::configs::Config; } + +#[test] +fn test_examples() { + for example in std::fs::read_dir("../examples").unwrap() { + let path = example.unwrap().path(); + eprintln!("Checking file {path:?}."); + let src = prelude_compile::Source::new_from_file(path).unwrap(); + let (mut i1, _, mut i3) = prelude_compile::Config::new().bundle_std().infos(); + prelude_compile::parse(&mut src.clone(), &std::sync::Arc::new(src)) + .unwrap() + .compile(&mut i1, prelude_compile::CompInfo::default()) + .unwrap() + .check(&mut i3, None) + .unwrap(); + } +} diff --git a/mers_lib/src/program/configs/mod.rs b/mers_lib/src/program/configs/mod.rs index 2b3ddf4..58468c4 100755 --- a/mers_lib/src/program/configs/mod.rs +++ b/mers_lib/src/program/configs/mod.rs @@ -7,15 +7,15 @@ use crate::{ program::run::CheckInfo, }; -mod with_base; -mod with_command_running; -mod with_get; -mod with_iters; -mod with_list; -mod with_math; -mod with_multithreading; -mod with_stdio; -mod with_string; +pub mod with_base; +pub mod with_command_running; +pub mod with_get; +pub mod with_iters; +pub mod with_list; +pub mod with_math; +pub mod with_multithreading; +pub mod with_stdio; +pub mod with_string; /// Usage: create an empty Config using Config::new(), use the methods to customize it, then get the Infos using Config::infos() /// bundle_* for bundles (combines multiple groups or even bundles) diff --git a/mers_lib/src/program/configs/with_list.rs b/mers_lib/src/program/configs/with_list.rs index b96c6e2..2be9828 100755 --- a/mers_lib/src/program/configs/with_list.rs +++ b/mers_lib/src/program/configs/with_list.rs @@ -1,6 +1,6 @@ use std::{ fmt::Display, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, RwLock}, }; use crate::{ @@ -17,16 +17,84 @@ impl Config { /// `as_list: fn` turns a tuple into a list /// `push: fn` adds an element to a list /// `pop: fn` removes the last element from a list. returns (element) or (). - /// TODO! /// `get_mut: fn` like get, but returns a reference to the object + /// TODO! + /// `remove_at: fn` [TODO] + /// `insert_at: fn` [TODO] pub fn with_list(self) -> Self { // TODO: Type with generics - self.add_type("List".to_string(), + self + .add_type("List".to_string(), Err(Arc::new(|s, i| { let mut src = Source::new_from_string_raw(s.to_owned()); let srca = Arc::new(src.clone()); let t = crate::parsing::types::parse_type(&mut src, &srca)?; Ok(Arc::new(ListT(crate::parsing::types::type_from_parsed(&t, i)?)))}))) + .add_var("get_mut".to_string(), Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + out: Arc::new(|a, _i| { + let mut out = Type::empty_tuple(); + for t in a.types.iter() { + if let Some(t) = t.as_any().downcast_ref::() { + if t.0.len() != 2 { + return Err(format!( + "get_mut: argument must be a 2-tuple `(&List<_>, Int)`." + ).into()); + } + if t.0[1].is_included_in_single(&data::int::IntT) { + if let Some(t) = t.0[0].dereference() { + for t in t.types.iter() { + if let Some(t) = t.as_any().downcast_ref::() { + out.add(Arc::new(data::reference::ReferenceT(t.0.clone()))); + } else { + return Err(format!( + "get_mut: first argument in tuple {t} isn't `&List<_>`." + ).into()); + } + } + } else { + return Err(format!( + "get_mut: first type in tuple {t} isn't a reference." + ).into()); + } + } else { + return Err(format!( + "get_mut: Second type in tuple {t} wasn't `Int`." + ).into()); + } + } else { + return Err(format!( + "get_mut: argument must be a 2-tuple `(&List<_>, Int)`." + ).into()); + } + } + Ok(out) + }), + run: Arc::new(|a, _i| { + let t = a.get(); + let t = t.as_any().downcast_ref::().unwrap(); + let i = t.0[1].get().as_any().downcast_ref::().unwrap().0.max(0) as usize; + let o = match t.0[0].get() + .as_any() + .downcast_ref::() + .unwrap() + .0 + .read() + .unwrap() + .get() + .as_any() + .downcast_ref::() + .unwrap().0.get(i) + { + Some(data) => { + Data::new(data::reference::Reference(Arc::clone(data))) + } + None => Data::empty_tuple(), + }; + o + }), + })) .add_var( "pop".to_string(), Data::new(data::function::Function { @@ -68,7 +136,7 @@ impl Config { .0 .pop() { - Some(data) => Data::one_tuple(data), + Some(data) => Data::one_tuple(data.read().unwrap().clone()), None => Data::empty_tuple(), } }), @@ -131,7 +199,7 @@ impl Config { .downcast_mut::() .unwrap() .0 - .push(tuple.0[1].clone()); + .push(Arc::new(RwLock::new(tuple.0[1].clone()))); Data::empty_tuple() }), }), @@ -152,7 +220,7 @@ impl Config { }), run: Arc::new(|a, _i| { if let Some(i) = a.get().iterable() { - Data::new(List(i.collect())) + Data::new(List(i.map(|v| Arc::new(RwLock::new(v))).collect())) } else { unreachable!("as_list called on non-iterable") } @@ -163,19 +231,29 @@ impl Config { } #[derive(Clone, Debug)] -pub struct List(Vec); +pub struct List(Vec>>); #[derive(Debug)] pub struct ListT(Type); impl MersData for List { fn is_eq(&self, other: &dyn MersData) -> bool { if let Some(other) = other.as_any().downcast_ref::() { - other.0 == self.0 + other.0.len() == self.0.len() + && self + .0 + .iter() + .zip(other.0.iter()) + .all(|(s, o)| *s.read().unwrap() == *o.read().unwrap()) } else { false } } fn iterable(&self) -> Option>> { - Some(Box::new(self.0.clone().into_iter())) + Some(Box::new( + self.0 + .clone() + .into_iter() + .map(|v| v.read().unwrap().clone()), + )) } fn clone(&self) -> Box { Box::new(Clone::clone(self)) @@ -183,7 +261,7 @@ impl MersData for List { fn as_type(&self) -> Type { let mut t = Type::empty(); for el in &self.0 { - t.add(Arc::new(el.get().as_type())); + t.add(Arc::new(el.read().unwrap().get().as_type())); } Type::new(ListT(t)) } @@ -235,7 +313,7 @@ impl Display for List { if i > 0 { write!(f, ", ")?; } - write!(f, "{}", c.get())?; + write!(f, "{}", c.read().unwrap().get())?; } write!(f, "]")?; Ok(())