make objects work better, especially destructuring

This commit is contained in:
Mark
2024-09-28 01:51:20 +02:00
parent 9c8e918440
commit c17ea580b2
41 changed files with 899 additions and 453 deletions

View File

@@ -58,8 +58,12 @@ pub trait StaticMersFunc: Sized + 'static + Send + Sync {
Some(Err(e)) => Err(e),
None => Err(CheckError::from(format!(
"unexpected argument of type {}, expected {}",
a.get().as_type(),
Type::new(data::function::FunctionT(Err(Arc::new(Self::types()))))
a.get().as_type().with_info(i),
Type::new(data::function::FunctionT(
Err(Arc::new(Self::types())),
crate::info::Info::neverused()
))
.with_info(i)
))),
}
})

View File

@@ -4,7 +4,7 @@ use crate::{
data::{self, Data, MersData, Type},
errors::CheckError,
info::Local,
program::run::CheckInfo,
program::run::{CheckInfo, CheckLocalGlobalInfo, RunLocalGlobalInfo},
};
pub mod gen;
@@ -63,7 +63,15 @@ impl Config {
}
pub fn new() -> Self {
let mut info_check: CheckInfo = Default::default();
let info_parsed = crate::program::parsed::Info::new(
crate::program::parsed::LocalGlobalInfo::new(Arc::new(Default::default())),
);
let mut info_check = CheckInfo::new(CheckLocalGlobalInfo::new(Arc::clone(
&info_parsed.global.object_fields,
)));
let info_run = crate::program::run::Info::new(RunLocalGlobalInfo::new(Arc::clone(
&info_parsed.global.object_fields,
)));
macro_rules! init_d {
($e:expr) => {
let t = $e;
@@ -89,8 +97,8 @@ impl Config {
init_d!(data::string::StringT);
Self {
globals: 0,
info_parsed: Default::default(),
info_run: Default::default(),
info_parsed,
info_run,
info_check,
}
}

View File

@@ -7,29 +7,46 @@ use crate::{
};
pub fn to_mers_func(
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result<Type, CheckError>
+ Send
+ Sync
+ 'static,
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
+ Send
+ Sync
+ 'static,
) -> data::function::Function {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(Info::neverused())),
out: Ok(Arc::new(move |a, _| out(a))),
run: Arc::new(move |a, _| run(a)),
out: Ok(Arc::new(move |a, i| out(a, i))),
run: Arc::new(move |a, i| run(a, i)),
inner_statements: None,
}
}
pub fn to_mers_func_with_in_type(
in_type: Type,
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result<Type, CheckError>
+ Send
+ Sync
+ 'static,
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
+ Send
+ Sync
+ 'static,
) -> data::function::Function {
to_mers_func(
move |a| {
move |a, i| {
if a.is_included_in(&in_type) {
out(a)
out(a, i)
} else {
Err(format!("Function argument must be {in_type}, but was {a}.").into())
Err(format!(
"Function argument must be {}, but was {}.",
in_type.with_info(i),
a.with_info(i)
)
.into())
}
},
run,
@@ -39,16 +56,19 @@ pub fn to_mers_func_with_in_type(
pub fn to_mers_func_with_in_out_types(
in_type: Type,
out_type: Type,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
+ Send
+ Sync
+ 'static,
) -> data::function::Function {
data::function::Function::new_static(vec![(in_type, out_type)], move |a, _| run(a))
data::function::Function::new_static(vec![(in_type, out_type)], move |a, i| run(a, i))
}
pub fn to_mers_func_concrete_string_to_any(
out_type: Type,
f: impl Fn(&str) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func_with_in_out_types(Type::new(data::string::StringT), out_type, move |a| {
to_mers_func_with_in_out_types(Type::new(data::string::StringT), out_type, move |a, _| {
f(a.get()
.as_any()
.downcast_ref::<data::string::String>()
@@ -75,7 +95,7 @@ pub fn to_mers_func_concrete_string_string_to_any(
Type::new(data::string::StringT),
])),
out_type,
move |a| {
move |a, _| {
let a = a.get();
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
let l = a[0].get();

View File

@@ -4,7 +4,7 @@ use std::{
};
use crate::{
data::{self, bool::bool_type, Data, Type},
data::{self, bool::bool_type, Data, MersTypeWInfo, Type},
errors::CheckError,
program::run::{CheckInfo, Info},
};
@@ -30,7 +30,7 @@ impl Config {
.add_var("lock_update", data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() == 2 {
@@ -42,23 +42,23 @@ impl Config {
match f.o(&arg) {
Ok(out) => {
if !out.is_included_in(&arg) {
return Err(format!("Function returns a value of type {out}, which isn't included in the type of the reference, {arg}.").into());
return Err(format!("Function returns a value of type {}, which isn't included in the type of the reference, {}.", out.with_info(i), arg.with_info(i)).into());
}
},
Err(e) => return Err(CheckError::new().msg_str(format!("Invalid argument type {arg} for function")).err(e)),
Err(e) => return Err(CheckError::new().msg_str(format!("Invalid argument type {} for function", arg.with_info(i))).err(e)),
}
} else {
return Err(format!("Arguments must be (reference, function)").into());
}
}
} else {
return Err(format!("Arguments must be (reference, function), but {arg_ref} isn't a reference").into());
return Err(format!("Arguments must be (reference, function), but {} isn't a reference", arg_ref.with_info(i)).into());
}
} else {
return Err(format!("Can't call lock_update on tuple type {t} with length != 2, which is part of the argument type {a}.").into());
return Err(format!("Can't call lock_update on tuple type {} with length != 2, which is part of the argument type {}.", t.with_info(i), a.with_info(i)).into());
}
} else {
return Err(format!("Can't call lock_update on non-tuple type {t}, which is part of the argument type {a}.").into());
return Err(format!("Can't call lock_update on non-tuple type {}, which is part of the argument type {}.", t.with_info(i), a.with_info(i)).into());
}
}
Ok(Type::empty_tuple())
@@ -98,10 +98,10 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
for t in &a.types {
if t.as_any().downcast_ref::<data::string::StringT>().is_none() && t.as_any().downcast_ref::<data::tuple::TupleT>().is_none() && t.iterable().is_none() {
return Err(format!("cannot get length of {t} (must be a tuple, string or iterable)").into());
return Err(format!("cannot get length of {} (must be a tuple, string or iterable)", t.with_info(i)).into());
}
}
Ok(Type::new(data::int::IntT))
@@ -174,7 +174,7 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into())
out: Ok(Arc::new(|a, i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {}", a.with_info(i)).into())
})),
run: Arc::new(|a, _i| {
if let Some(r) = a

View File

@@ -6,8 +6,9 @@ use std::{
};
use crate::{
data::{self, Data, MersData, MersType, Type},
data::{self, object::ObjectFieldsMap, Data, MersData, MersDataWInfo, MersType, Type},
errors::CheckError,
info::DisplayInfo,
program::{self, run::CheckInfo},
};
@@ -29,7 +30,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(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)))) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![
@@ -37,13 +38,13 @@ impl Config {
Type::new(data::string::StringT),
Type::new(data::string::StringT),
])),
Arc::new(data::object::ObjectT(vec![("run_command_error".to_owned(), Type::new(data::string::StringT))]))
Arc::new(data::object::ObjectT::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Type::new(data::string::StringT))]))
]))
} else {
return Err(format!("run_command called with invalid arguments (must be (String, Iter<String>))").into());
}
})),
run: Arc::new(|a, _i| {
run: Arc::new(|a, i| {
let a = a.get();
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
@@ -52,7 +53,7 @@ impl Config {
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
args.get().iterable().unwrap(),
);
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::<Result<Vec<_>, _>>()?;
match Command::new(&cmd.0)
.args(args)
.output()
@@ -73,7 +74,7 @@ impl Config {
Data::new(data::string::String(stderr)),
])))
}
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
Err(e) => Ok(Data::new(data::object::Object::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Data::new(data::string::String(e.to_string())))]))),
}
}),
inner_statements: None,
@@ -84,17 +85,17 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(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)))) {
Ok(Type::newm(vec![
Arc::new(ChildProcessT),
Arc::new(data::object::ObjectT(vec![("run_command_error".to_owned(), Type::new(data::string::StringT))]))
Arc::new(data::object::ObjectT::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Type::new(data::string::StringT))]))
]))
} else {
return Err(format!("spawn_command called with invalid arguments (must be (String, Iter<String>))").into());
}
})),
run: Arc::new(|a, _i| {
run: Arc::new(|a, i| {
let a = a.get();
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
@@ -103,7 +104,7 @@ impl Config {
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
args.get().iterable().unwrap(),
);
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::<Result<Vec<_>, _>>()?;
match Command::new(&cmd.0)
.args(args)
.stdin(Stdio::piped())
@@ -117,7 +118,7 @@ impl Config {
let c = BufReader::new(child.stderr.take().unwrap());
Ok(Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c))))))
}
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
Err(e) => Ok(Data::new(data::object::Object::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Data::new(data::string::String(e.to_string())))]))),
}
}),
inner_statements: None,
@@ -128,14 +129,14 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![data::bool::bool_type()])),
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_exited called on non-ChildProcess type {a}").into());
return Err(format!("childproc_exited called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -156,7 +157,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::int::IntT),
@@ -165,7 +166,7 @@ impl Config {
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_await called on non-ChildProcess type {a}").into());
return Err(format!("childproc_await called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -190,11 +191,11 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(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)))) {
Ok(data::bool::bool_type())
} else {
return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter<Byte>)` type {a}").into());
return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter<Byte>)` type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -219,11 +220,11 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) {
Ok(data::bool::bool_type())
} else {
return Err(format!("childproc_write_string called on non-`(ChildProcess, String)` type {a}").into());
return Err(format!("childproc_write_string called on non-`(ChildProcess, String)` type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -248,14 +249,14 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_read_byte called on non-ChildProcess type {a}").into());
return Err(format!("childproc_read_byte called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -277,14 +278,14 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_readerr_byte called on non-ChildProcess type {a}").into());
return Err(format!("childproc_readerr_byte called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -306,14 +307,14 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
return Err(format!("childproc_read_line called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -335,14 +336,14 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
Arc::new(data::tuple::TupleT(vec![])),
]))
} else {
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
return Err(format!("childproc_read_line called on non-ChildProcess type {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -376,6 +377,9 @@ pub struct ChildProcess(
#[derive(Clone, Debug)]
pub struct ChildProcessT;
impl MersData for ChildProcess {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
None
}
@@ -410,6 +414,13 @@ impl Display for ChildProcess {
}
}
impl MersType for ChildProcessT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn iterable(&self) -> Option<Type> {
None
}

View File

@@ -1,7 +1,7 @@
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data, Type},
data::{self, Data, MersTypeWInfo, Type},
program::{self, run::CheckInfo},
};
@@ -15,7 +15,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
let mut out = Type::empty();
for a in a.types.iter() {
if let Some(t) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
@@ -25,7 +25,7 @@ impl Config {
if !t.0[1].is_included_in_single(&data::int::IntT) {
return Err(format!(
"called get with non-int index of type {}",
t.0[1]
t.0[1].with_info(i)
)
.into());
}
@@ -33,12 +33,16 @@ impl Config {
out.add_all(&v);
} else {
return Err(format!(
"called get on non-gettable type {t}, part of {a}"
"called get on non-gettable type {}, part of {}",
t.with_info(i),
a.with_info(i)
)
.into());
}
} else {
return Err(format!("called get on non-tuple type {a}").into());
return Err(
format!("called get on non-tuple type {}", a.with_info(i)).into()
);
}
}
Ok(Type::newm(vec![

View File

@@ -7,9 +7,10 @@ use crate::{
data::{
self,
function::{Function, FunctionT},
Data, MersData, MersType, Type,
Data, MersData, MersType, MersTypeWInfo, Type,
},
errors::CheckError,
info::DisplayInfo,
program::{self, run::CheckInfo},
};
@@ -49,7 +50,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
for a in &a.types {
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
@@ -70,7 +71,8 @@ impl Config {
}
} else {
return Err(format!(
"for_each called on tuple not containing iterable and function: {v} is {}",
"for_each called on tuple not containing iterable and function: {} is {}",
v.with_info(i),
if v.iterable().is_some() { "iterable" } else { "not iterable" },
).into());
}
@@ -133,13 +135,13 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
let data = if let Some(a) = a.iterable() {
a
} else {
return Err(format!("cannot call enumerate on non-iterable type {a}.").into());
return Err(format!("cannot call enumerate on non-iterable type {}.", a.with_info(i)).into());
};
Ok(Type::new(IterT::new(ItersT::Enumerate, data)?))
Ok(Type::new(IterT::new(ItersT::Enumerate, data, i)?))
})),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
inner_statements: None,
@@ -150,13 +152,13 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
let data = if let Some(a) = a.iterable() {
a
} else {
return Err(format!("cannot call chain on non-iterable type {a}.").into());
return Err(format!("cannot call chain on non-iterable type {}.", a.with_info(i)).into());
};
Ok(Type::new(IterT::new(ItersT::Chained, data)?))
Ok(Type::new(IterT::new(ItersT::Chained, data, i)?))
})),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
inner_statements: None,
@@ -172,6 +174,7 @@ fn genfunc_iter_and_func(
) -> data::function::Function {
fn iter_out_arg(
a: &Type,
i: &mut CheckInfo,
name: &str,
func: impl Fn(FunctionT) -> ItersT + Sync + Send,
) -> Result<Type, CheckError> {
@@ -184,14 +187,16 @@ fn genfunc_iter_and_func(
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())?));
out.add(Arc::new(IterT::new(func(f), v.clone(), i)?));
} else {
return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {a}", t.0[1]).into());
return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {}", t.0[1].with_info(i), a.with_info(i)).into());
}
}
} else {
return Err(format!(
"cannot call {name} on non-iterable type {t}, which is part of {a}."
"cannot call {name} on non-iterable type {}, which is part of {}.",
t.with_info(i),
a.with_info(i)
)
.into());
}
@@ -202,7 +207,7 @@ fn genfunc_iter_and_func(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(move |a, _i| iter_out_arg(a, name, |f| ft(f)))),
out: Ok(Arc::new(move |a, i| iter_out_arg(a, i, name, |f| ft(f)))),
run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@@ -225,10 +230,12 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
) -> data::function::Function {
fn iter_out_arg<T: MersType>(
a: &Type,
i: &mut CheckInfo,
name: &str,
func: impl Fn(&T) -> ItersT + Sync + Send,
type_sample: &T,
) -> Result<Type, CheckError> {
let type_sample = type_sample.with_info(i);
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@@ -238,14 +245,16 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
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())?));
out.add(Arc::new(IterT::new(func(f), v.clone(), i)?));
} else {
return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {a}", t.0[1]).into());
return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {}", t.0[1].with_info(i), a.with_info(i)).into());
}
}
} else {
return Err(format!(
"cannot call {name} on non-iterable type {t}, which is part of {a}."
"cannot call {name} on non-iterable type {}, which is part of {}.",
t.with_info(i),
a.with_info(i)
)
.into());
}
@@ -256,8 +265,8 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(move |a, _i| {
iter_out_arg(a, name, |f: &T| ft(f), type_sample)
out: Ok(Arc::new(move |a, i| {
iter_out_arg(a, i, name, |f: &T| ft(f), type_sample)
})),
run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
@@ -303,6 +312,9 @@ pub struct Iter(pub Iters, pub Data);
#[derive(Clone, Debug)]
pub struct IterT(pub ItersT, pub Type, pub Type);
impl MersData for Iter {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
@@ -396,7 +408,14 @@ impl MersData for Iter {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> data::Type {
Type::new(IterT::new(self.0.as_type(), self.1.get().as_type()).unwrap())
Type::new(
IterT::new(
self.0.as_type(),
self.1.get().as_type(),
&crate::info::Info::neverused(),
)
.unwrap(),
)
}
fn as_any(&self) -> &dyn std::any::Any {
self
@@ -409,7 +428,8 @@ impl MersData for Iter {
}
}
impl IterT {
pub fn new(iter: ItersT, data: Type) -> Result<Self, CheckError> {
/// `i` is only used for errors (this is important for `as_type()`)
pub fn new(iter: ItersT, data: Type, i: &CheckInfo) -> Result<Self, CheckError> {
let t = match &iter {
ItersT::Map(f) => f.o(&data)?,
ItersT::Filter(f) => {
@@ -417,7 +437,8 @@ impl IterT {
data.clone()
} else {
return Err(format!(
"Iter:Filter, but function doesn't return bool for argument {data}."
"Iter:Filter, but function doesn't return bool for argument {}.",
data.with_info(&i)
)
.into());
}
@@ -450,7 +471,8 @@ impl IterT {
out
} else {
return Err(format!(
"Cannot create a chain from an iterator over the non-iterator type {data}."
"Cannot create a chain from an iterator over the non-iterator type {}.",
data.with_info(i)
)
.into());
}
@@ -460,6 +482,13 @@ impl IterT {
}
}
impl MersType for IterT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "<Iter: {}>", self.2.with_display(info))
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
self.2.is_same_type_as(&other.2)
@@ -496,11 +525,6 @@ impl Display for Iter {
write!(f, "<Iter>")
}
}
impl Display for IterT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Iter: {}>", self.2)
}
}
impl Iters {
fn as_type(&self) -> ItersT {
match self {
@@ -527,15 +551,24 @@ fn genfunc_iter_in_val_out(
Function {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
out: Ok(Arc::new(move |a, _i| {
out: Ok(Arc::new(move |a, i| {
if let Some(iter_over) = a.iterable() {
if iter_over.is_included_in(&iter_type) {
Ok(out_type.clone())
} else {
Err(format!("Cannot call function {name} on iterator over type {a}, which isn't {iter_type}.").into())
Err(format!(
"Cannot call function {name} on iterator over type {}, which isn't {}.",
a.with_info(i),
iter_type.with_info(i)
)
.into())
}
} else {
Err(format!("Cannot call function {name} on non-iterable type {a}.").into())
Err(format!(
"Cannot call function {name} on non-iterable type {}.",
a.with_info(i)
)
.into())
}
})),
run: Arc::new(run),

View File

@@ -1,11 +1,9 @@
use std::{
fmt::Display,
sync::{Arc, Mutex, RwLock},
};
use std::sync::{Arc, Mutex, RwLock};
use crate::{
data::{self, Data, MersData, MersType, Type},
data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
errors::CheckError,
info::DisplayInfo,
parsing::{statements::to_string_literal, Source},
program::{self, run::CheckInfo},
};
@@ -34,7 +32,7 @@ impl Config {
.add_var("get_mut", data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(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::<data::tuple::TupleT>() {
@@ -50,18 +48,18 @@ impl Config {
out.add(Arc::new(data::tuple::TupleT(vec![Type::new(data::reference::ReferenceT(t.0.clone()))])));
} else {
return Err(format!(
"get_mut: first argument in tuple {t} isn't `&List<_>`."
"get_mut: first argument in tuple {} isn't `&List<_>`.", t.with_info(i)
).into());
}
}
} else {
return Err(format!(
"get_mut: first type in tuple {t} isn't a reference."
"get_mut: first type in tuple {} isn't a reference.", t.with_info(i)
).into());
}
} else {
return Err(format!(
"get_mut: Second type in tuple {t} wasn't `Int`."
"get_mut: Second type in tuple {} wasn't `Int`.", t.with_info(i)
).into());
}
} else {
@@ -103,7 +101,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if let Some(a) = a.dereference() {
let mut out = Type::empty();
for t in a.types.iter() {
@@ -111,7 +109,7 @@ impl Config {
out.add_all(&t.0);
} else {
return Err(format!(
"pop: found a reference to {t}, which is not a list"
"pop: found a reference to {}, which is not a list", t.with_info(i)
).into());
}
}
@@ -120,7 +118,7 @@ impl Config {
Arc::new(data::tuple::TupleT(vec![]))
]))
} else {
return Err(format!("pop: not a reference: {a}").into());
return Err(format!("pop: not a reference: {}", a.with_info(i)).into());
}
})),
run: Arc::new(|a, _i| {
@@ -151,7 +149,7 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() != 2 {
@@ -166,22 +164,22 @@ impl Config {
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
if !new.is_included_in(&t.0) {
return Err(format!(
"push: found a reference to {t}, which is a list which can't contain elements of type {new}"
"push: found a reference to {}, which is a list which can't contain elements of type {}", t.with_info(i), new.with_info(i)
).into());
}
} else {
return Err(format!(
"push: found a reference to {t}, which is not a list"
"push: found a reference to {}, which is not a list", t.with_info(i)
).into());
}
}
} else {
return Err(format!(
"push: first element in tuple not a reference: {a}"
"push: first element in tuple not a reference: {}", a.with_info(i)
).into());
}
} else {
return Err(format!("push: not a tuple: {t}")
return Err(format!("push: not a tuple: {}", t.with_info(i))
.into());
}
}
@@ -214,12 +212,12 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
if let Some(v) = a.iterable() {
Ok(Type::new(ListT(v)))
} else {
Err(format!(
"cannot iterate over type {a}"
"cannot iterate over type {}", a.with_info(i)
).into())
}
})),
@@ -251,6 +249,17 @@ impl Clone for List {
#[derive(Debug)]
pub struct ListT(pub Type);
impl MersData for List {
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "[")?;
for (i, c) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
c.read().unwrap().get().display(info, f)?;
}
write!(f, "]")?;
Ok(())
}
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0.len() == self.0.len()
@@ -288,6 +297,17 @@ impl MersData for List {
}
}
impl MersType for ListT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(
f,
"List<{}>",
to_string_literal(&self.0.with_display(info).to_string(), '>')
)
}
fn iterable(&self) -> Option<Type> {
Some(self.0.clone())
}
@@ -324,25 +344,6 @@ impl MersType for ListT {
Some(Type::new(Self(self.0.simplify_for_display(info))))
}
}
impl Display for List {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
for (i, c) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", c.read().unwrap().get())?;
}
write!(f, "]")?;
Ok(())
}
}
impl Display for ListT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "List<{}>", to_string_literal(&self.0.to_string(), '>'))?;
Ok(())
}
}
impl List {
pub fn inner_type(&self) -> Type {
let mut t = Type::empty();

View File

@@ -326,7 +326,7 @@ fn num_iter_to_num(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(move |a, _i| {
out: Ok(Arc::new(move |a, i| {
if let Some(a) = a.iterable() {
let int_type = Type::new(data::int::IntT);
if a.is_included_in(&int_type) {
@@ -343,7 +343,7 @@ fn num_iter_to_num(
if a.is_included_in(&int_float_type) {
Ok(int_float_type)
} else {
Err(format!("argument passed to {func_name} must be an iterator over values of type Int/String, but was an iterator over values of type {a}.").into())
Err(format!("argument passed to {func_name} must be an iterator over values of type Int/String, but was an iterator over values of type {}.", a.with_info(i)).into())
}
}
}

View File

@@ -5,8 +5,9 @@ use std::{
};
use crate::{
data::{self, Data, MersData, MersType, Type},
data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
errors::CheckError,
info::DisplayInfo,
parsing::{statements::to_string_literal, Source},
program::{self, run::CheckInfo},
};
@@ -57,10 +58,10 @@ impl Config {
.add_var("thread_finished", data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if !t.as_any().is::<ThreadT>() {
return Err(CheckError::new().msg_str(format!("Cannot call thread_finished on a value of type {t}, which isn't a thread but part of the argument {a}.")));
return Err(CheckError::new().msg_str(format!("Cannot call thread_finished on a value of type {}, which isn't a thread but part of the argument {}.", t.with_info(i), a.with_info(i))));
}
}
Ok(data::bool::bool_type())
@@ -78,13 +79,13 @@ impl Config {
.add_var("thread_await", data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| {
out: Ok(Arc::new(|a, i| {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ThreadT>() {
out.add_all(&t.0);
} else {
return Err(CheckError::new().msg_str(format!("Cannot call thread_await on a value of type {t}, which isn't a thread but part of the argument {a}.")));
return Err(CheckError::new().msg_str(format!("Cannot call thread_await on a value of type {}, which isn't a thread but part of the argument {}.", t.with_info(i), a.with_info(i))));
}
}
Ok(out)
@@ -112,6 +113,9 @@ pub struct Thread(
pub struct ThreadT(pub Type);
impl MersData for Thread {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
@@ -132,6 +136,17 @@ impl MersData for Thread {
}
}
impl MersType for ThreadT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(
f,
"Thread<{}>",
to_string_literal(&self.0.with_display(info).to_string(), '>')
)
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
self.0.is_same_type_as(&other.0)
@@ -172,8 +187,3 @@ impl Display for Thread {
write!(f, "<Thread>")
}
}
impl Display for ThreadT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Thread<{}>", to_string_literal(&self.0.to_string(), '>'))
}
}

View File

@@ -4,7 +4,7 @@ use std::{
};
use crate::{
data::{self, Data, Type},
data::{self, Data, MersDataWInfo, Type},
program::{self, run::CheckInfo},
};
@@ -66,9 +66,9 @@ impl Config {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
run: Arc::new(|a, _i| {
run: Arc::new(|a, i| {
let a2 = a.get();
eprintln!("{} :: {}", a2.as_type(), a2);
eprintln!("{} :: {}", a2.as_type().with_info(i), a2.with_info(i));
drop(a2);
Ok(a)
}),
@@ -81,8 +81,8 @@ impl Config {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
eprint!("{}", a.get());
run: Arc::new(|a, i| {
eprint!("{}", a.get().with_info(i));
_ = std::io::stderr().lock().flush();
Ok(Data::empty_tuple())
}),
@@ -95,8 +95,8 @@ impl Config {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
eprintln!("{}", a.get());
run: Arc::new(|a, i| {
eprintln!("{}", a.get().with_info(i));
Ok(Data::empty_tuple())
}),
inner_statements: None,
@@ -108,8 +108,8 @@ impl Config {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
print!("{}", a.get());
run: Arc::new(|a, i| {
print!("{}", a.get().with_info(i));
_ = std::io::stdout().lock().flush();
Ok(Data::empty_tuple())
}),
@@ -122,8 +122,8 @@ impl Config {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
println!("{}", a.get());
run: Arc::new(|a, i| {
println!("{}", a.get().with_info(i));
Ok(Data::empty_tuple())
}),
inner_statements: None,

View File

@@ -1,4 +1,4 @@
use crate::data::{self, Data, Type};
use crate::data::{self, Data, MersDataWInfo, Type};
use super::{
gen::{function::func, AnyOrNone, IterToList, OneOf, OneOrNone},
@@ -58,19 +58,22 @@ impl Config {
.add_var(
"concat",
util::to_mers_func(
|a| {
|a, i| {
if a.iterable().is_some() {
Ok(Type::new(data::string::StringT))
} else {
Err(format!("concat called on non-iterable type {a}").into())
Err(
format!("concat called on non-iterable type {}", a.with_info(i))
.into(),
)
}
},
|a| {
|a, i| {
Ok(Data::new(data::string::String(
a.get()
.iterable()
.unwrap()
.map(|v| v.map(|v| v.get().to_string()))
.map(|v| v.map(|v| v.get().with_info(i).to_string()))
.collect::<Result<_, _>>()?,
)))
},
@@ -79,8 +82,12 @@ impl Config {
.add_var(
"to_string",
util::to_mers_func(
|_a| Ok(Type::new(data::string::StringT)),
|a| Ok(Data::new(data::string::String(a.get().to_string()))),
|_a, _| Ok(Type::new(data::string::StringT)),
|a, i| {
Ok(Data::new(data::string::String(
a.get().with_info(i).to_string(),
)))
},
),
)
.add_var(

View File

@@ -3,9 +3,9 @@ use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data},
errors::{CheckError, EColor, SourceRange},
info::{self, Local},
info,
parsing::Source,
program::{self},
program,
};
use super::{CompInfo, MersStatement};

View File

@@ -6,7 +6,7 @@ use std::{
use crate::{
errors::{CheckError, SourceRange},
info,
info::{self, DisplayInfo},
};
#[cfg(feature = "parse")]
@@ -113,7 +113,7 @@ pub struct Local {
pub vars: HashMap<String, (usize, usize)>,
pub vars_count: usize,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct LocalGlobalInfo {
pub depth: usize,
pub enable_hooks: bool,
@@ -129,11 +129,33 @@ pub struct LocalGlobalInfo {
)>,
>,
>,
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
}
impl LocalGlobalInfo {
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
Self {
depth: 0,
enable_hooks: false,
save_info_at: Default::default(),
object_fields,
object_fields_rev: Default::default(),
}
}
}
impl info::Local for Local {
type VariableIdentifier = String;
type VariableData = (usize, usize);
type Global = LocalGlobalInfo;
fn neverused_global() -> Self::Global {
Self::Global {
depth: 0,
enable_hooks: false,
save_info_at: Default::default(),
object_fields: Default::default(),
object_fields_rev: Default::default(),
}
}
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
self.vars_count += 1;
self.vars.insert(id, value);
@@ -147,4 +169,10 @@ impl info::Local for Local {
fn duplicate(&self) -> Self {
self.clone()
}
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
DisplayInfo {
object_fields: &global.object_fields,
object_fields_rev: &global.object_fields_rev,
}
}
}

View File

@@ -1,7 +1,7 @@
use crate::{
data::object::ObjectFieldsMap,
errors::{CheckError, SourceRange},
info,
program::{self},
info, program,
};
use super::{CompInfo, MersStatement};
@@ -22,10 +22,15 @@ impl MersStatement for Object {
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
Ok(Box::new(program::run::object::Object {
pos_in_src: self.pos_in_src.clone(),
elems: self
fields: self
.elems
.iter()
.map(|(n, v)| -> Result<_, CheckError> { Ok((n.clone(), v.compile(info, comp)?)) })
.map(|(n, v)| -> Result<_, CheckError> {
Ok((
info.global.object_fields.get_or_add_field(n),
v.compile(info, comp)?,
))
})
.collect::<Result<Vec<_>, _>>()?,
}))
}

View File

@@ -1,7 +1,6 @@
use crate::{
errors::{CheckError, EColor, SourceRange},
info::Local,
program::{self},
program,
};
use super::{CompInfo, MersStatement};

View File

@@ -1,7 +1,6 @@
use crate::{
data::{self, Data, MersData, Type},
errors::{CheckError, SourceRange},
info::Local,
};
use super::MersStatement;

View File

@@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::{
data::{self, Data, Type},
data::{self, Data, MersTypeWInfo, Type},
errors::{CheckError, SourceRange},
};
@@ -28,7 +28,7 @@ impl MersStatement for Loop {
if let Some(i) = i.as_any().downcast_ref::<data::tuple::TupleT>() {
if i.0.len() > 1 {
return Err(format!(
"Loop: Inner statement must return ()/(T), not {t} (because of {i}, a tuple of length > 1)."
"Loop: Inner statement must return ()/(T), not {} (because of {}, a tuple of length > 1).", t.with_info(info), i.with_info(info)
)
.into());
} else {
@@ -40,7 +40,7 @@ impl MersStatement for Loop {
}
} else {
return Err(format!(
"Loop: Inner statement must return ()/(T), not {t} (because of {i}, which isn't a tuple)."
"Loop: Inner statement must return ()/(T), not {} (because of {}, which isn't a tuple).", t.with_info(info), i.with_info(info)
)
.into());
}

View File

@@ -8,7 +8,7 @@ use std::{
use crate::{
data::{self, Data, Type},
errors::{CheckError, EColor, SourceRange},
info,
info::{self, DisplayInfo},
};
#[cfg(feature = "run")]
@@ -126,10 +126,21 @@ pub type CheckInfo = info::Info<CheckLocal>;
pub struct RunLocal {
pub vars: Vec<Arc<RwLock<Data>>>,
}
#[derive(Default, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct RunLocalGlobalInfo {
/// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error.
pub limit_runtime: Option<Instant>,
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
}
impl RunLocalGlobalInfo {
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
Self {
limit_runtime: None,
object_fields,
object_fields_rev: Default::default(),
}
}
}
#[derive(Default, Clone)]
pub struct CheckLocal {
@@ -142,7 +153,7 @@ pub struct CheckLocal {
>,
>,
}
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct CheckLocalGlobalInfo {
pub depth: usize,
pub enable_hooks: bool,
@@ -160,6 +171,8 @@ pub struct CheckLocalGlobalInfo {
>,
>,
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>,
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
}
impl CheckLocalGlobalInfo {
pub fn show_warnings_to_stderr(&mut self) {
@@ -171,6 +184,18 @@ impl CheckLocalGlobalInfo {
eprintln!("{}", e.display(theme));
}));
}
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
Self {
depth: 0,
enable_hooks: false,
show_warnings: None,
save_info_at: Default::default(),
unused_try_statements: Default::default(),
object_fields,
object_fields_rev: Default::default(),
}
}
}
impl Debug for CheckLocalGlobalInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -186,6 +211,13 @@ impl info::Local for RunLocal {
type VariableIdentifier = usize;
type VariableData = Arc<RwLock<Data>>;
type Global = RunLocalGlobalInfo;
fn neverused_global() -> Self::Global {
Self::Global {
limit_runtime: None,
object_fields: Default::default(),
object_fields_rev: Default::default(),
}
}
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
while self.vars.len() <= id {
@@ -214,11 +246,28 @@ impl info::Local for RunLocal {
.collect(),
}
}
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
DisplayInfo {
object_fields: &global.object_fields,
object_fields_rev: &global.object_fields_rev,
}
}
}
impl info::Local for CheckLocal {
type VariableIdentifier = usize;
type VariableData = Type;
type Global = CheckLocalGlobalInfo;
fn neverused_global() -> Self::Global {
Self::Global {
depth: 0,
enable_hooks: false,
show_warnings: None,
save_info_at: Default::default(),
unused_try_statements: Default::default(),
object_fields: Default::default(),
object_fields_rev: Default::default(),
}
}
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
while self.vars.len() <= id {
self.vars.push(Type::empty());
@@ -240,4 +289,10 @@ impl info::Local for CheckLocal {
fn duplicate(&self) -> Self {
self.clone()
}
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
DisplayInfo {
object_fields: &global.object_fields,
object_fields_rev: &global.object_fields_rev,
}
}
}

View File

@@ -1,7 +1,7 @@
use std::collections::VecDeque;
use std::collections::HashMap;
use crate::{
data::{self, object::ObjectT, Data, MersType, Type},
data::{self, object::ObjectT, Data, Type},
errors::{CheckError, EColor, SourceRange},
};
@@ -10,7 +10,7 @@ use super::MersStatement;
#[derive(Debug)]
pub struct Object {
pub pos_in_src: SourceRange,
pub elems: Vec<(String, Box<dyn MersStatement>)>,
pub fields: Vec<(usize, Box<dyn MersStatement>)>,
}
impl MersStatement for Object {
fn check_custom(
@@ -18,75 +18,16 @@ impl MersStatement for Object {
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
let mut assign_types = if let Some(init_to) = init_to {
let mut acc = (0..self.elems.len())
.map(|_| Type::empty())
.collect::<VecDeque<_>>();
let mut init_fields = if let Some(init_to) = init_to {
let print_is_part_of = init_to.types.len() > 1;
let mut init_fields = HashMap::new();
for t in init_to.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
if self.elems.len() == t.0.len() {
for (i, ((sn, _), (tn, t))) in self.elems.iter().zip(t.0.iter()).enumerate()
{
if sn != tn {
return Err(CheckError::new().msg(vec![
("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None),
(t.simplified_as_string(info), Some(EColor::InitFrom)),
if print_is_part_of {
(", which is part of ".to_owned(), None)
} else {
(String::new(), None)
},
if print_is_part_of {
(init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else {
(String::new(), None)
},
(" - field mismatch: ".to_owned(), None),
(sn.to_owned(), None),
(" != ".to_owned(), None),
(tn.to_owned(), None),
]));
}
acc[i].add_all(&t);
}
} else {
return Err(CheckError::new().msg(vec![
("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None),
(t.simplified_as_string(info), Some(EColor::InitFrom)),
if print_is_part_of {
(", which is part of ".to_owned(), None)
} else {
(format!(""), None)
},
if print_is_part_of {
(init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else {
(format!(""), None)
},
(" - source has ".to_owned(), None),
(if self.elems.len() > t.0.len() {
format!("less fields ({}, not {})", t.0.len(), self.elems.len())
} else {
format!(
"more fields. Either ignore those fields (`{}`) - or remove them from the type (`... := [{}] ...`)",
t.0.iter()
.skip(self.elems.len())
.enumerate()
.map(|(i, (n, _))| if i == 0 {
format!("{n}: _")
} else {
format!(", {n}: _")
})
.collect::<String>(),
data::object::ObjectT(t.0.iter().take(self.elems.len()).cloned().collect()).simplified_as_string(info)
)
}, None)
]));
for (field, t) in t.iter() {
init_fields
.entry(*field)
.or_insert_with(Type::empty)
.add_all(t);
}
} else {
return Err(CheckError::new().msg(vec![
@@ -111,20 +52,39 @@ impl MersStatement for Object {
]));
}
}
Some(acc)
Some(init_fields)
} else {
None
};
Ok(Type::new(data::object::ObjectT(
self.elems
Ok(Type::new(data::object::ObjectT::new(
self.fields
.iter()
.map(|(n, v)| -> Result<_, CheckError> {
.map(|(field, v)| -> Result<_, CheckError> {
Ok((
n.clone(),
*field,
v.check(
info,
if let Some(it) = &mut assign_types {
Some(it.pop_front().unwrap())
if let Some(f) = &mut init_fields {
Some(if let Some(s) = f.remove(field) {
s
} else {
return Err(CheckError::new().msg(vec![
("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None),
(
init_to.as_ref().unwrap().simplified_as_string(info),
Some(EColor::InitFrom),
),
(
format!(
" - field {} is missing",
info.display_info().get_object_field_name(*field)
),
None,
),
]));
})
} else {
None
}
@@ -136,8 +96,8 @@ impl MersStatement for Object {
)))
}
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(Data::new(data::object::Object(
self.elems
Ok(Data::new(data::object::Object::new(
self.fields
.iter()
.map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?)))
.collect::<Result<_, _>>()?,
@@ -150,7 +110,7 @@ impl MersStatement for Object {
self.pos_in_src.clone()
}
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
self.elems.iter().map(|(_, s)| s.as_ref()).collect()
self.fields.iter().map(|(_, s)| s.as_ref()).collect()
}
fn as_any(&self) -> &dyn std::any::Any {
self

View File

@@ -66,7 +66,7 @@ impl MersStatement for Try {
"try: #{} is not a function, type is {} within {}.",
i + 1,
ft.simplified_as_string(info),
func.simplify_for_display(info),
func.simplify_for_display(info).with_info(info),
))
.src(vec![
(self.source_range(), None),