From 18cd3ee0ae5b6657fc414749506bc46111121c21 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Mon, 1 Jul 2024 20:51:09 +0200 Subject: [PATCH] functions no longer modify state, funcrefs exist you can use &func as a function, too. this allows the function to mutate its inner state. --- mers/Cargo.toml | 4 +- mers_lib/Cargo.toml | 2 +- mers_lib/examples/01_user_scripts.rs | 2 +- mers_lib/src/data/function.rs | 39 +++- mers_lib/src/data/mod.rs | 13 ++ mers_lib/src/data/reference.rs | 85 +++++++- mers_lib/src/info/mod.rs | 2 +- mers_lib/src/program/configs/util.rs | 2 +- mers_lib/src/program/configs/with_base.rs | 23 +-- .../program/configs/with_command_running.rs | 20 +- mers_lib/src/program/configs/with_get.rs | 2 +- mers_lib/src/program/configs/with_iters.rs | 189 +++++++++++------- mers_lib/src/program/configs/with_list.rs | 8 +- mers_lib/src/program/configs/with_math.rs | 12 +- .../program/configs/with_multithreading.rs | 23 +-- mers_lib/src/program/configs/with_stdio.rs | 12 +- mers_lib/src/program/parsed/function.rs | 2 +- mers_lib/src/program/parsed/include_mers.rs | 2 +- mers_lib/src/program/run/chain.rs | 38 ++-- mers_lib/src/program/run/function.rs | 7 +- mers_lib/src/program/run/try.rs | 34 +--- 21 files changed, 330 insertions(+), 191 deletions(-) diff --git a/mers/Cargo.toml b/mers/Cargo.toml index 2dddd58..445334c 100644 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers" -version = "0.8.25" +version = "0.9.0" edition = "2021" license = "MIT OR Apache-2.0" description = "dynamically typed but type-checked programming language" @@ -15,7 +15,7 @@ default = ["colored-output"] colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"] [dependencies] -mers_lib = "0.8.25" +mers_lib = "0.9.0" # mers_lib = { path = "../mers_lib" } clap = { version = "4.3.19", features = ["derive"] } colored = { version = "2.1.0", optional = true } diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index 01fb1b6..d644ad4 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers_lib" -version = "0.8.25" +version = "0.9.0" edition = "2021" license = "MIT OR Apache-2.0" description = "library to use the mers language in other projects" diff --git a/mers_lib/examples/01_user_scripts.rs b/mers_lib/examples/01_user_scripts.rs index a696819..f06de81 100644 --- a/mers_lib/examples/01_user_scripts.rs +++ b/mers_lib/examples/01_user_scripts.rs @@ -23,7 +23,7 @@ fn main() -> Result<(), CheckError> { // use the function to decorate these 3 test strings for input in ["my test string", "Main Menu", "O.o"] { - let result = func.run(Data::new(data::string::String(input.to_owned())))?; + let result = func.run_immut(Data::new(data::string::String(input.to_owned())))?; let result = result.get(); let result = &result .as_any() diff --git a/mers_lib/src/data/function.rs b/mers_lib/src/data/function.rs index a6a1a7a..1c94779 100755 --- a/mers_lib/src/data/function.rs +++ b/mers_lib/src/data/function.rs @@ -6,14 +6,14 @@ use std::{ use crate::{ errors::CheckError, + info::Local, program::run::{CheckInfo, Info}, }; use super::{Data, MersData, MersType, Type}; -#[derive(Clone)] pub struct Function { - pub info: Arc, + pub info: Info, pub info_check: Arc>, pub out: Arc Result + Send + Sync>, pub run: @@ -23,20 +23,31 @@ pub struct Function { Arc>, )>, } +impl Clone for Function { + fn clone(&self) -> Self { + Self { + info: self.info.duplicate(), + info_check: self.info_check.clone(), + out: self.out.clone(), + run: self.run.clone(), + inner_statements: self.inner_statements.clone(), + } + } +} impl Function { pub fn new( out: impl Fn(&Type) -> Result + Send + Sync + 'static, run: impl Fn(Data) -> Result + Send + Sync + 'static, ) -> Self { Self { - info: Arc::new(crate::info::Info::neverused()), + info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), out: Arc::new(move |a, _| out(a)), run: Arc::new(move |a, _| run(a)), inner_statements: None, } } - pub fn with_info_run(&self, info: Arc) -> Self { + pub fn with_info_run(&self, info: Info) -> Self { Self { info, info_check: Arc::clone(&self.info_check), @@ -57,8 +68,11 @@ impl Function { drop(lock); (self.out)(arg, &mut info) } - pub fn run(&self, arg: Data) -> Result { - (self.run)(arg, &mut self.info.as_ref().clone()) + pub fn run_mut(&mut self, arg: Data) -> Result { + (self.run)(arg, &mut self.info) + } + pub fn run_immut(&self, arg: Data) -> Result { + (self.run)(arg, &mut self.info.duplicate()) } pub fn get_as_type(&self) -> FunctionT { let out = Arc::clone(&self.out); @@ -73,10 +87,16 @@ impl Function { } impl MersData for Function { + fn executable(&self) -> Option { + Some(self.get_as_type()) + } + fn execute(&self, arg: Data) -> Option> { + Some(self.run_immut(arg)) + } fn iterable(&self) -> Option>>> { - let s = Clone::clone(self); + let mut s = Clone::clone(self); Some(Box::new(std::iter::from_fn(move || { - match s.run(Data::empty_tuple()) { + match s.run_mut(Data::empty_tuple()) { Err(e) => Some(Err(e)), Ok(v) => { if let Some(v) = v.one_tuple_content() { @@ -122,6 +142,9 @@ impl FunctionT { } } impl MersType for FunctionT { + fn executable(&self) -> Option { + Some(self.clone()) + } fn iterable(&self) -> Option { // if this function can be called with an empty tuple and returns `()` or `(T)`, it can act as an iterator with type `T`. if let Ok(t) = self.o(&Type::empty_tuple()) { diff --git a/mers_lib/src/data/mod.rs b/mers_lib/src/data/mod.rs index 7917954..e40c278 100755 --- a/mers_lib/src/data/mod.rs +++ b/mers_lib/src/data/mod.rs @@ -19,6 +19,15 @@ pub mod tuple; pub mod defs; pub trait MersData: Any + Debug + Display + Send + Sync { + /// must be the same as the `executable` impl on the MersType + #[allow(unused_variables)] + fn executable(&self) -> Option { + None + } + #[allow(unused_variables)] + fn execute(&self, arg: Data) -> Option> { + None + } fn iterable(&self) -> Option>>> { None } @@ -38,6 +47,10 @@ pub trait MersData: Any + Debug + Display + Send + Sync { } pub trait MersType: Any + Debug + Display + Send + Sync { + #[allow(unused_variables)] + fn executable(&self) -> Option { + None + } /// If Some(T), calling `iterable` on the MersData this MersType belongs to /// Should return Some(I), where I is an Iterator which only returns items of type T. fn iterable(&self) -> Option { diff --git a/mers_lib/src/data/reference.rs b/mers_lib/src/data/reference.rs index 89c7aab..59fcb31 100755 --- a/mers_lib/src/data/reference.rs +++ b/mers_lib/src/data/reference.rs @@ -4,12 +4,63 @@ use std::{ sync::{Arc, RwLock}, }; +use crate::errors::CheckError; + use super::{Data, MersData, MersType, Type}; #[derive(Debug, Clone)] pub struct Reference(pub Arc>); impl MersData for Reference { + fn executable(&self) -> Option { + let inner = self.0.read().unwrap(); + let inner = inner.get(); + if let Some(func) = inner + .as_ref() + .as_any() + .downcast_ref::() + { + Some(func.get_as_type()) + } else { + None + } + } + fn execute(&self, arg: Data) -> Option> { + let mut inner = self.0.write().unwrap(); + let mut inner = inner.get_mut(); + if let Some(func) = inner + .as_mut() + .mut_any() + .downcast_mut::() + { + Some(func.run_mut(arg)) + } else { + None + } + } + fn iterable(&self) -> Option>>> { + let inner = Arc::clone(&self.0); + Some(Box::new(std::iter::from_fn(move || { + match inner + .write() + .unwrap() + .get_mut() + .mut_any() + .downcast_mut::() + .unwrap() + .run_mut(Data::empty_tuple()) + { + Err(e) => Some(Err(e)), + Ok(v) => { + if let Some(v) = v.one_tuple_content() { + Some(Ok(v)) + } else { + None + } + } + } + }))) + } fn is_eq(&self, other: &dyn MersData) -> bool { if let Some(other) = other.as_any().downcast_ref::() { *other.0.write().unwrap() == *self.0.write().unwrap() @@ -37,6 +88,38 @@ impl MersData for Reference { #[derive(Debug, Clone)] pub struct ReferenceT(pub Type); impl MersType for ReferenceT { + fn executable(&self) -> Option { + let mut funcs: Vec = vec![]; + for func in self.0.types.iter() { + funcs.push(Clone::clone( + func.as_any() + .downcast_ref::()?, + )); + } + Some(super::function::FunctionT(Ok(Arc::new(move |a| { + let mut out = Type::empty(); + for func in funcs.iter() { + out.add_all(&func.o(a)?); + } + Ok(out) + })))) + } + fn iterable(&self) -> Option { + let mut out = Type::empty(); + for func in self.0.types.iter() { + out.add_all( + &func + .as_any() + .downcast_ref::()? + .iterable()?, + ); + } + if !out.types.is_empty() { + Some(out) + } else { + None + } + } fn is_same_type_as(&self, other: &dyn MersType) -> bool { if let Some(o) = other.as_any().downcast_ref::() { self.0.is_same_type_as(&o.0) @@ -76,7 +159,7 @@ impl MersType for ReferenceT { impl Display for Reference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "&{}", self.0.write().unwrap().get()) + write!(f, "&{}", self.0.read().unwrap().get()) } } impl Display for ReferenceT { diff --git a/mers_lib/src/info/mod.rs b/mers_lib/src/info/mod.rs index ac625d0..cae5e14 100755 --- a/mers_lib/src/info/mod.rs +++ b/mers_lib/src/info/mod.rs @@ -52,7 +52,7 @@ impl Local for Info { } fn duplicate(&self) -> Self { Self { - scopes: vec![self.scopes[0].duplicate()], + scopes: self.scopes.iter().map(|v| v.duplicate()).collect(), global: self.global.clone(), } } diff --git a/mers_lib/src/program/configs/util.rs b/mers_lib/src/program/configs/util.rs index 3c31001..eb02940 100644 --- a/mers_lib/src/program/configs/util.rs +++ b/mers_lib/src/program/configs/util.rs @@ -11,7 +11,7 @@ pub fn to_mers_func( run: impl Fn(Data) -> Result + Send + Sync + 'static, ) -> data::function::Function { data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(Info::neverused())), out: Arc::new(move |a, _| out(a)), run: Arc::new(move |a, _| run(a)), diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index 1136814..30a4332 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -27,7 +27,7 @@ impl Config { // .add_var("try".to_string(), get_try(false)) // .add_var("try_allow_unused".to_string(), get_try(true)) .add_var("lock_update".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for t in a.types.iter() { @@ -37,7 +37,7 @@ impl Config { if let Some(arg) = arg_ref.dereference() { let func = &t.0[1]; for func_t in func.types.iter() { - if let Some(f) = func_t.as_any().downcast_ref::() { + if let Some(f) = func_t.executable() { match f.o(&arg) { Ok(out) => { if !out.is_included_in(&arg) { @@ -69,14 +69,13 @@ impl Config { let arg_ref = arg_ref.as_any().downcast_ref::().unwrap(); let mut arg = arg_ref.0.write().unwrap(); let func = a.0[1].get(); - let func = func.as_any().downcast_ref::().unwrap(); - *arg = func.run(arg.clone())?; + *arg = func.execute(arg.clone()).unwrap()?; Ok(Data::empty_tuple()) }), inner_statements: None, })) .add_var("sleep".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| if a.is_included_in(&Type::newm(vec![ Arc::new(data::int::IntT), @@ -105,7 +104,7 @@ impl Config { inner_statements: None, })) .add_var("exit".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| if a.is_included_in_single(&data::int::IntT) { Ok(Type::empty()) @@ -118,7 +117,7 @@ impl Config { inner_statements: None, })) .add_var("panic".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| if a.is_included_in_single(&data::string::StringT) { Ok(Type::empty()) @@ -140,7 +139,7 @@ impl Config { .add_var( "len".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for t in &a.types { @@ -168,7 +167,7 @@ impl Config { .add_var( "eq".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for t in &a.types { @@ -204,7 +203,7 @@ impl Config { .add_var( "mkref".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| Ok(Type::new(data::reference::ReferenceT(a.clone())))), run: Arc::new(|a, _i| { @@ -216,7 +215,7 @@ impl Config { .add_var( "deref".to_string(), Data::new(data::function::Function { - info: Arc::new(Info::neverused()), + info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into()) }), @@ -239,7 +238,7 @@ impl Config { // fn get_try(allow_unused_functions: bool) -> Data { // Data::new(data::function::Function { -// info: Arc::new(Info::neverused()), +// info: Info::neverused(), // info_check: Arc::new(Mutex::new(CheckInfo::neverused())), // out: Arc::new(move |a, _i| { // let mut out = Type::empty(); diff --git a/mers_lib/src/program/configs/with_command_running.rs b/mers_lib/src/program/configs/with_command_running.rs index 6bcbb82..c1648e8 100755 --- a/mers_lib/src/program/configs/with_command_running.rs +++ b/mers_lib/src/program/configs/with_command_running.rs @@ -27,7 +27,7 @@ impl Config { .add_var( "run_command".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) { @@ -82,7 +82,7 @@ impl Config { .add_var( "spawn_command".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) { @@ -126,7 +126,7 @@ impl Config { .add_var( "childproc_exited".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { @@ -154,7 +154,7 @@ impl Config { .add_var( "childproc_await".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { @@ -187,7 +187,7 @@ impl Config { .add_var( "childproc_write_bytes".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.types.iter().all(|a| a.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) { @@ -216,7 +216,7 @@ impl Config { .add_var( "childproc_write_string".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) { @@ -245,7 +245,7 @@ impl Config { .add_var( "childproc_read_byte".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { @@ -274,7 +274,7 @@ impl Config { .add_var( "childproc_readerr_byte".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { @@ -303,7 +303,7 @@ impl Config { .add_var( "childproc_read_line".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { @@ -332,7 +332,7 @@ impl Config { .add_var( "childproc_readerr_line".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in_single(&ChildProcessT) { diff --git a/mers_lib/src/program/configs/with_get.rs b/mers_lib/src/program/configs/with_get.rs index 9ccc9f9..9730fe1 100755 --- a/mers_lib/src/program/configs/with_get.rs +++ b/mers_lib/src/program/configs/with_get.rs @@ -13,7 +13,7 @@ impl Config { self.add_var( "get".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let mut out = Type::empty(); diff --git a/mers_lib/src/program/configs/with_iters.rs b/mers_lib/src/program/configs/with_iters.rs index 4cf1f80..d932117 100755 --- a/mers_lib/src/program/configs/with_iters.rs +++ b/mers_lib/src/program/configs/with_iters.rs @@ -47,7 +47,7 @@ impl Config { .add_var( "for_each".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for a in &a.types { @@ -58,7 +58,7 @@ impl Config { f.types .iter() .map(|t| { - t.as_any().downcast_ref::() + t.executable() }) .collect::>>(), ) { @@ -88,17 +88,15 @@ impl Config { run: Arc::new(|a, _i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { - if let (Some(iter), Some(f)) = ( - v.get().iterable(), - f.get().as_any().downcast_ref::(), - ) { + if let Some(iter) = v.get().iterable() { + let f = f.get(); for v in iter { - f.run(v?)?; + f.execute(v?).unwrap()?; } Ok(Data::empty_tuple()) } else { return Err( - "for_each called on tuple not containing iterable and function".into() + "for_each called on tuple not containing iterable and function (not an iterable)".into() ); } } else { @@ -129,11 +127,11 @@ impl Config { ) .add_var("take".to_string(), Data::new(genfunc_iter_and_arg("take", |_: &data::int::IntT| ItersT::Take, |v: &data::int::Int| { Iters::Take(v.0.max(0) as _) - }))) + }, &data::int::IntT))) .add_var( "enumerate".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let data = if let Some(a) = a.iterable() { @@ -150,7 +148,7 @@ impl Config { .add_var( "chain".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let data = if let Some(a) = a.iterable() { @@ -167,56 +165,98 @@ impl Config { } } -fn iter_out_arg( - a: &Type, - name: &str, - func: impl Fn(&T) -> ItersT + Sync + Send, -) -> Result { - let mut out = Type::empty(); - for t in a.types.iter() { - if let Some(t) = t.as_any().downcast_ref::() { - if t.0.len() != 2 { - return Err(format!("cannot call {name} on tuple where len != 2").into()); - } - if let Some(v) = t.0[0].iterable() { - for f in t.0[1].types.iter() { - if let Some(f) = f.as_any().downcast_ref::() { - out.add(Arc::new(IterT::new(func(f), v.clone())?)); - } else { - return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {a}", t.0[1]).into()); - } - } - } else { - return Err(format!( - "cannot call {name} on non-iterable type {t}, which is part of {a}." - ) - .into()); - } - } - } - Ok(out) -} - fn genfunc_iter_and_func( name: &'static str, ft: impl Fn(FunctionT) -> ItersT + Send + Sync + 'static, - fd: impl Fn(Function) -> Iters + Send + Sync + 'static, + fd: impl Fn(Data) -> Iters + Send + Sync + 'static, ) -> data::function::Function { - genfunc_iter_and_arg( - name, - move |v| ft(Clone::clone(v)), - move |v| fd(Clone::clone(v)), - ) + fn iter_out_arg( + a: &Type, + name: &str, + func: impl Fn(FunctionT) -> ItersT + Sync + Send, + ) -> Result { + let mut out = Type::empty(); + for t in a.types.iter() { + if let Some(t) = t.as_any().downcast_ref::() { + if t.0.len() != 2 { + return Err(format!("cannot call {name} on tuple where len != 2").into()); + } + if let Some(v) = t.0[0].iterable() { + for f in t.0[1].types.iter() { + if let Some(f) = f.executable() { + out.add(Arc::new(IterT::new(func(f), v.clone())?)); + } else { + return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {a}", t.0[1]).into()); + } + } + } else { + return Err(format!( + "cannot call {name} on non-iterable type {t}, which is part of {a}." + ) + .into()); + } + } + } + Ok(out) + } + data::function::Function { + info: program::run::Info::neverused(), + info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + out: Arc::new(move |a, _i| iter_out_arg(a, name, |f| ft(f))), + run: Arc::new(move |a, _i| { + if let Some(tuple) = a.get().as_any().downcast_ref::() { + if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { + Ok(Data::new(Iter(fd(f.clone()), v.clone()))) + } else { + return Err("{name} called on tuple with len < 2".into()); + } + } else { + return Err("{name} called on non-tuple".into()); + } + }), + inner_statements: None, + } } fn genfunc_iter_and_arg( name: &'static str, ft: impl Fn(&T) -> ItersT + Send + Sync + 'static, fd: impl Fn(&D) -> Iters + Send + Sync + 'static, + type_sample: &'static T, ) -> data::function::Function { + fn iter_out_arg( + a: &Type, + name: &str, + func: impl Fn(&T) -> ItersT + Sync + Send, + type_sample: &T, + ) -> Result { + let mut out = Type::empty(); + for t in a.types.iter() { + if let Some(t) = t.as_any().downcast_ref::() { + if t.0.len() != 2 { + return Err(format!("cannot call {name} on tuple where len != 2").into()); + } + if let Some(v) = t.0[0].iterable() { + for f in t.0[1].types.iter() { + if let Some(f) = f.as_any().downcast_ref::() { + out.add(Arc::new(IterT::new(func(f), v.clone())?)); + } else { + return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {a}", t.0[1]).into()); + } + } + } else { + return Err(format!( + "cannot call {name} on non-iterable type {t}, which is part of {a}." + ) + .into()); + } + } + } + Ok(out) + } data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), - out: Arc::new(move |a, _i| iter_out_arg(a, name, |f: &T| ft(f))), + out: Arc::new(move |a, _i| iter_out_arg(a, name, |f: &T| ft(f), type_sample)), run: Arc::new(move |a, _i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { @@ -238,10 +278,10 @@ fn genfunc_iter_and_arg( #[derive(Clone, Debug)] pub enum Iters { - Map(data::function::Function), - Filter(data::function::Function), - FilterMap(data::function::Function), - MapWhile(data::function::Function), + Map(Data), + Filter(Data), + FilterMap(Data), + MapWhile(Data), Take(usize), Enumerate, Chained, @@ -268,14 +308,18 @@ impl MersData for Iter { Some(match &self.0 { Iters::Map(f) => { let f = Clone::clone(f); - Box::new(self.1.get().iterable()?.map(move |v| f.run(v?))) + Box::new(self.1.get().iterable()?.map(move |v| { + f.get() + .execute(v?) + .ok_or_else(|| CheckError::from("called map with non-function argument"))? + })) } Iters::Filter(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable()?.filter_map(move |v| { match v { - Ok(v) => match f.run(v.clone()) { - Ok(f) => { + Ok(v) => match f.get().execute(v.clone()) { + Some(Ok(f)) => { if f.get() .as_any() .downcast_ref::() @@ -286,7 +330,10 @@ impl MersData for Iter { None } } - Err(e) => Some(Err(e)), + Some(Err(e)) => Some(Err(e)), + None => Some(Err(CheckError::from( + "called filter with non-function argument", + ))), }, Err(e) => Some(Err(e)), } @@ -295,9 +342,12 @@ impl MersData for Iter { Iters::FilterMap(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable()?.filter_map(move |v| match v { - Ok(v) => match f.run(v) { - Ok(r) => Some(Ok(r.one_tuple_content()?)), - Err(e) => Some(Err(e)), + Ok(v) => match f.get().execute(v) { + Some(Ok(r)) => Some(Ok(r.one_tuple_content()?)), + Some(Err(e)) => Some(Err(e)), + None => Some(Err(CheckError::from( + "called filter_map with non-function argument", + ))), }, Err(e) => Some(Err(e)), })) @@ -305,9 +355,12 @@ impl MersData for Iter { Iters::MapWhile(f) => { let f = Clone::clone(f); Box::new(self.1.get().iterable()?.map_while(move |v| match v { - Ok(v) => match f.run(v) { - Ok(r) => Some(Ok(r.one_tuple_content()?)), - Err(e) => Some(Err(e)), + Ok(v) => match f.get().execute(v) { + Some(Ok(r)) => Some(Ok(r.one_tuple_content()?)), + Some(Err(e)) => Some(Err(e)), + None => Some(Err(CheckError::from( + "called map_while with non-function argument", + ))), }, Err(e) => Some(Err(e)), })) @@ -449,10 +502,10 @@ impl Display for IterT { impl Iters { fn as_type(&self) -> ItersT { match self { - Self::Map(f) => ItersT::Map(f.get_as_type()), - Self::Filter(f) => ItersT::Filter(f.get_as_type()), - Self::FilterMap(f) => ItersT::FilterMap(f.get_as_type()), - Self::MapWhile(f) => ItersT::MapWhile(f.get_as_type()), + Self::Map(f) => ItersT::Map(f.get().executable().unwrap()), + Self::Filter(f) => ItersT::Filter(f.get().executable().unwrap()), + Self::FilterMap(f) => ItersT::FilterMap(f.get().executable().unwrap()), + Self::MapWhile(f) => ItersT::MapWhile(f.get().executable().unwrap()), Self::Take(_) => ItersT::Take, Self::Enumerate => ItersT::Enumerate, Self::Chained => ItersT::Chained, @@ -470,7 +523,7 @@ fn genfunc_iter_in_val_out( + 'static, ) -> Function { Function { - info: Arc::new(crate::info::Info::neverused()), + info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), out: Arc::new(move |a, _i| { if let Some(iter_over) = a.iterable() { diff --git a/mers_lib/src/program/configs/with_list.rs b/mers_lib/src/program/configs/with_list.rs index 182f913..8931853 100755 --- a/mers_lib/src/program/configs/with_list.rs +++ b/mers_lib/src/program/configs/with_list.rs @@ -32,7 +32,7 @@ impl Config { let t = crate::parsing::types::parse_type(&mut src, &srca)?; Ok(Arc::new(Type::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: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let mut out = Type::empty_tuple(); @@ -101,7 +101,7 @@ impl Config { .add_var( "pop".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if let Some(a) = a.dereference() { @@ -149,7 +149,7 @@ impl Config { .add_var( "push".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for t in a.types.iter() { @@ -212,7 +212,7 @@ impl Config { .add_var( "as_list".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if let Some(v) = a.iterable() { diff --git a/mers_lib/src/program/configs/with_math.rs b/mers_lib/src/program/configs/with_math.rs index cf3c3ea..5b4bca6 100755 --- a/mers_lib/src/program/configs/with_math.rs +++ b/mers_lib/src/program/configs/with_math.rs @@ -71,7 +71,7 @@ impl Config { .add_var( "parse_float".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in(&Type::new(data::string::StringT)) { @@ -105,7 +105,7 @@ impl Config { .add_var( "parse_int".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in(&Type::new(data::string::StringT)) { @@ -139,7 +139,7 @@ impl Config { .add_var( "signum".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_included_in(&Type::newm(vec![ @@ -255,7 +255,7 @@ fn num_iter_to_num( func: impl Fn(Result, Result) -> Result + Send + Sync + 'static, ) -> data::function::Function { data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(move |a, _i| { if let Some(a) = a.iterable() { @@ -320,7 +320,7 @@ fn two_num_tuple_to_num( func_ff: impl Fn(f64, f64) -> Result + Send + Sync + 'static, ) -> data::function::Function { data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| two_tuple_to_num_impl_check(a, func_name)), run: Arc::new(move |a, _i| { @@ -406,7 +406,7 @@ fn ltgtoe_function( op: impl Fn(IntOrFloatOrNothing, IntOrFloatOrNothing) -> bool + Send + Sync + 'static, ) -> data::function::Function { data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(move |a, _i| { if let Some(iter_type) = a.iterable() { diff --git a/mers_lib/src/program/configs/with_multithreading.rs b/mers_lib/src/program/configs/with_multithreading.rs index 3c878ff..2de9bf5 100755 --- a/mers_lib/src/program/configs/with_multithreading.rs +++ b/mers_lib/src/program/configs/with_multithreading.rs @@ -30,12 +30,12 @@ impl Config { .add_var( "thread".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let mut out = Type::empty(); for t in a.types.iter() { - if let Some(f) = t.as_any().downcast_ref::() { + if let Some(f) = t.executable() { match f.o(&Type::empty_tuple()) { Ok(t) => out.add_all(&t), Err(e) => return Err(CheckError::new().msg_str(format!("Can't call thread on a function which can't be called on an empty tuple: ")).err(e)) @@ -47,24 +47,15 @@ impl Config { Ok(Type::new(ThreadT(out))) }), run: Arc::new(|a, _i| { - let a = a.get(); - if let Some(f) = a - .as_any() - .downcast_ref::() - .cloned() - { - Ok(Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn( - move || f.run(Data::empty_tuple()), - ))))))) - } else { - return Err("thread called, but arg wasn't a function".into()); - } + Ok(Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn( + move || a.get().execute(Data::empty_tuple()).unwrap(), + ))))))) }), inner_statements: None, }), ) .add_var("thread_finished".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { for t in a.types.iter() { @@ -85,7 +76,7 @@ impl Config { inner_statements: None, })) .add_var("thread_await".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { let mut out = Type::empty(); diff --git a/mers_lib/src/program/configs/with_stdio.rs b/mers_lib/src/program/configs/with_stdio.rs index cd75cd8..5d4ce0a 100755 --- a/mers_lib/src/program/configs/with_stdio.rs +++ b/mers_lib/src/program/configs/with_stdio.rs @@ -22,7 +22,7 @@ impl Config { self.add_var( "read_line".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| { if a.is_zero_tuple() { @@ -50,7 +50,7 @@ impl Config { .add_var( "debug".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|a, _i| Ok(a.clone())), run: Arc::new(|a, _i| { @@ -65,7 +65,7 @@ impl Config { .add_var( "eprint".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|_a, _i| Ok(Type::empty_tuple())), run: Arc::new(|a, _i| { @@ -79,7 +79,7 @@ impl Config { .add_var( "eprintln".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|_a, _i| Ok(Type::empty_tuple())), run: Arc::new(|a, _i| { @@ -92,7 +92,7 @@ impl Config { .add_var( "print".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|_a, _i| Ok(Type::empty_tuple())), run: Arc::new(|a, _i| { @@ -106,7 +106,7 @@ impl Config { .add_var( "println".to_string(), Data::new(data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(|_a, _i| Ok(Type::empty_tuple())), run: Arc::new(|a, _i| { diff --git a/mers_lib/src/program/parsed/function.rs b/mers_lib/src/program/parsed/function.rs index 2b39661..c7b5bbc 100755 --- a/mers_lib/src/program/parsed/function.rs +++ b/mers_lib/src/program/parsed/function.rs @@ -36,7 +36,7 @@ impl MersStatement for Function { Ok(Box::new(program::run::function::Function { pos_in_src: self.pos_in_src.clone(), func_no_info: data::function::Function { - info: Arc::new(program::run::Info::neverused()), + info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Arc::new(move |a, i| { arg2.check(i, Some(a))?; diff --git a/mers_lib/src/program/parsed/include_mers.rs b/mers_lib/src/program/parsed/include_mers.rs index 11471f2..cbb93a9 100644 --- a/mers_lib/src/program/parsed/include_mers.rs +++ b/mers_lib/src/program/parsed/include_mers.rs @@ -54,7 +54,7 @@ impl MersStatement for IncludeMers { chained: Box::new(program::run::function::Function { pos_in_src: self.pos_in_src.clone(), func_no_info: data::function::Function { - info: Arc::new(info::Info::neverused()), + info: info::Info::neverused(), info_check: Arc::new(Mutex::new(info::Info::neverused())), out: Arc::new(move |_, i| compiled.check(&mut i.duplicate(), None)), run: Arc::new(move |_, i| compiled2.run(&mut i.duplicate())), diff --git a/mers_lib/src/program/run/chain.rs b/mers_lib/src/program/run/chain.rs index 4591558..e65cdf5 100755 --- a/mers_lib/src/program/run/chain.rs +++ b/mers_lib/src/program/run/chain.rs @@ -31,10 +31,7 @@ impl MersStatement for Chain { info.global.enable_hooks = prev_enable_hooks; let mut o = Type::empty(); for func in &func.types { - if let Some(func) = func - .as_any() - .downcast_ref::() - { + if let Some(func) = func.executable() { match func.o(&arg) { Ok(t) => o.add_all(&t), Err(e) => { @@ -89,28 +86,25 @@ impl MersStatement for Chain { let f = self.first.run(info)?; let c = self.chained.run(info)?; let c = c.get(); - if let Some(func) = c.as_any().downcast_ref::() { - match func.run(f) { - Ok(v) => Ok(v), - Err(e) => Err(if let Some(_) = &self.as_part_of_include { - CheckError::new().err_with_diff_src(e).src(vec![( - self.pos_in_src.clone(), - Some(EColor::StacktraceDescendHashInclude), - )]) - } else { - CheckError::new().err(e).src(vec![ - (self.pos_in_src.clone(), None), - (self.source_range(), Some(EColor::StacktraceDescend)), - ]) - }), - } - } else { - Err(CheckError::new() + match c.execute(f) { + Some(Ok(v)) => Ok(v), + Some(Err(e)) => Err(if let Some(_) = &self.as_part_of_include { + CheckError::new().err_with_diff_src(e).src(vec![( + self.pos_in_src.clone(), + Some(EColor::StacktraceDescendHashInclude), + )]) + } else { + CheckError::new().err(e).src(vec![ + (self.pos_in_src.clone(), None), + (self.source_range(), Some(EColor::StacktraceDescend)), + ]) + }), + None => Err(CheckError::new() .msg_str("tried to chain with non-function".to_owned()) .src(vec![( self.chained.source_range(), Some(EColor::ChainWithNonFunction), - )])) + )])), } } fn has_scope(&self) -> bool { diff --git a/mers_lib/src/program/run/function.rs b/mers_lib/src/program/run/function.rs index 67e6254..838cd23 100755 --- a/mers_lib/src/program/run/function.rs +++ b/mers_lib/src/program/run/function.rs @@ -1,8 +1,7 @@ -use std::sync::Arc; - use crate::{ data::{self, Data, MersData, Type}, errors::{CheckError, SourceRange}, + info::Local, }; use super::MersStatement; @@ -26,9 +25,7 @@ impl MersStatement for Function { Ok(self.func_no_info.as_type()) } fn run_custom(&self, info: &mut super::Info) -> Result { - Ok(Data::new( - self.func_no_info.with_info_run(Arc::new(info.clone())), - )) + Ok(Data::new(self.func_no_info.with_info_run(info.duplicate()))) } fn has_scope(&self) -> bool { true diff --git a/mers_lib/src/program/run/try.rs b/mers_lib/src/program/run/try.rs index 9f5173d..31556fb 100644 --- a/mers_lib/src/program/run/try.rs +++ b/mers_lib/src/program/run/try.rs @@ -53,7 +53,7 @@ impl MersStatement for Try { let mut func_res = Type::empty(); let mut func_err = None; for ft in func.types.iter() { - if let Some(ft) = ft.as_any().downcast_ref::() { + if let Some(ft) = ft.executable() { match ft.o(&Type::newm(vec![Arc::clone(arg)])) { Ok(res) => { func_res.add_all(&res); @@ -107,32 +107,18 @@ impl MersStatement for Try { let ar = arg.get(); let a = ar.as_ref(); let arg_type = a.as_type(); - let functions = self - .funcs - .iter() - .map(|v| { - Ok::<_, CheckError>( - v.run(info)? - .get() - .as_any() - .downcast_ref::() - .unwrap() - .clone(), - ) - }) - .collect::, _>>()?; - let mut found = None; - for (i, func) in functions.iter().enumerate() { - match func.get_as_type().o(&arg_type) { - Ok(_) => { - found = Some(i); - break; + for func in self.funcs.iter() { + let func = func.run(info)?; + let func = func.get(); + match func.executable().map(|func| func.o(&arg_type)) { + Some(Ok(_)) => { + drop(ar); + return func.execute(arg).unwrap(); } - Err(_) => (), + None | Some(Err(_)) => (), } } - drop(ar); - functions[found.expect("try: no function found")].run(arg) + panic!("try: no function found") } fn has_scope(&self) -> bool { true