functions no longer modify state, funcrefs exist

you can use &func as a function, too.
this allows the function to mutate its
inner state.
This commit is contained in:
Mark 2024-07-01 20:51:09 +02:00
parent 7acaafaa2f
commit 18cd3ee0ae
21 changed files with 330 additions and 191 deletions

View File

@ -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 }

View File

@ -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"

View File

@ -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()

View File

@ -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<Info>,
pub info: Info,
pub info_check: Arc<Mutex<CheckInfo>>,
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
pub run:
@ -23,20 +23,31 @@ pub struct Function {
Arc<Box<dyn crate::program::run::MersStatement>>,
)>,
}
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<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + 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<Info>) -> 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<Data, CheckError> {
(self.run)(arg, &mut self.info.as_ref().clone())
pub fn run_mut(&mut self, arg: Data) -> Result<Data, CheckError> {
(self.run)(arg, &mut self.info)
}
pub fn run_immut(&self, arg: Data) -> Result<Data, CheckError> {
(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<crate::data::function::FunctionT> {
Some(self.get_as_type())
}
fn execute(&self, arg: Data) -> Option<Result<Data, CheckError>> {
Some(self.run_immut(arg))
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
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<crate::data::function::FunctionT> {
Some(self.clone())
}
fn iterable(&self) -> Option<Type> {
// 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()) {

View File

@ -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<crate::data::function::FunctionT> {
None
}
#[allow(unused_variables)]
fn execute(&self, arg: Data) -> Option<Result<Data, CheckError>> {
None
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
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<crate::data::function::FunctionT> {
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<Type> {

View File

@ -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<RwLock<Data>>);
impl MersData for Reference {
fn executable(&self) -> Option<crate::data::function::FunctionT> {
let inner = self.0.read().unwrap();
let inner = inner.get();
if let Some(func) = inner
.as_ref()
.as_any()
.downcast_ref::<crate::data::function::Function>()
{
Some(func.get_as_type())
} else {
None
}
}
fn execute(&self, arg: Data) -> Option<Result<Data, CheckError>> {
let mut inner = self.0.write().unwrap();
let mut inner = inner.get_mut();
if let Some(func) = inner
.as_mut()
.mut_any()
.downcast_mut::<crate::data::function::Function>()
{
Some(func.run_mut(arg))
} else {
None
}
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
let inner = Arc::clone(&self.0);
Some(Box::new(std::iter::from_fn(move || {
match inner
.write()
.unwrap()
.get_mut()
.mut_any()
.downcast_mut::<crate::data::function::Function>()
.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::<Self>() {
*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<crate::data::function::FunctionT> {
let mut funcs: Vec<crate::data::function::FunctionT> = vec![];
for func in self.0.types.iter() {
funcs.push(Clone::clone(
func.as_any()
.downcast_ref::<crate::data::function::FunctionT>()?,
));
}
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<Type> {
let mut out = Type::empty();
for func in self.0.types.iter() {
out.add_all(
&func
.as_any()
.downcast_ref::<crate::data::function::FunctionT>()?
.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>() {
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 {

View File

@ -52,7 +52,7 @@ impl<L: Local> Local for Info<L> {
}
fn duplicate(&self) -> Self {
Self {
scopes: vec![self.scopes[0].duplicate()],
scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
global: self.global.clone(),
}
}

View File

@ -11,7 +11,7 @@ pub fn to_mers_func(
run: impl Fn(Data) -> Result<Data, CheckError> + 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)),

View File

@ -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::<data::function::FunctionT>() {
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::<data::reference::Reference>().unwrap();
let mut arg = arg_ref.0.write().unwrap();
let func = a.0[1].get();
let func = func.as_any().downcast_ref::<data::function::Function>().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();

View File

@ -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::<data::tuple::TupleT>().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::<data::tuple::TupleT>().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::<data::tuple::TupleT>().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) {

View File

@ -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();

View File

@ -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::<data::function::FunctionT>()
t.executable()
})
.collect::<Option<Vec<_>>>(),
) {
@ -88,17 +88,15 @@ impl Config {
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
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::<data::function::Function>(),
) {
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<T: MersType>(
a: &Type,
name: &str,
func: impl Fn(&T) -> ItersT + Sync + Send,
) -> Result<Type, CheckError> {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
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::<T>() {
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<Type, CheckError> {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
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::<data::tuple::Tuple>() {
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<T: MersType, D: MersData>(
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<T: MersType>(
a: &Type,
name: &str,
func: impl Fn(&T) -> ItersT + Sync + Send,
type_sample: &T,
) -> Result<Type, CheckError> {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
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::<T>() {
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::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -238,10 +278,10 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
#[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::<data::bool::Bool>()
@ -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() {

View File

@ -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() {

View File

@ -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<isize, f64>, Result<isize, f64>) -> Result<isize, f64> + 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<f64, CheckError> + 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() {

View File

@ -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::<data::function::FunctionT>() {
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::<data::function::Function>()
.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();

View File

@ -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| {

View File

@ -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))?;

View File

@ -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())),

View File

@ -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::<crate::data::function::FunctionT>()
{
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::<crate::data::function::Function>() {
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 {

View File

@ -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<Data, CheckError> {
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

View File

@ -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::<data::function::FunctionT>() {
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::<data::function::Function>()
.unwrap()
.clone(),
)
})
.collect::<Result<Vec<_>, _>>()?;
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