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

@ -15,7 +15,7 @@ default = ["colored-output"]
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"] colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
[dependencies] [dependencies]
mers_lib = "0.9.2" # mers_lib = "0.9.2"
# mers_lib = { path = "../mers_lib" } mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] } clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true } colored = { version = "2.1.0", optional = true }

View File

@ -132,12 +132,12 @@ fn main() {
eprintln!("{e:?}"); eprintln!("{e:?}");
exit(24); exit(24);
} }
Ok(compiled) => match check(&*compiled, i3) { Ok(compiled) => match check_mut(&*compiled, &mut i3) {
Err(e) => { Err(e) => {
eprintln!("{e:?}"); eprintln!("{e:?}");
exit(28); exit(28);
} }
Ok(output_type) => eprintln!("{output_type}"), Ok(output_type) => eprintln!("{}", output_type.with_info(&i3)),
}, },
} }
} }

View File

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use mers_lib::{ use mers_lib::{
data::{Data, Type}, data::{Data, MersDataWInfo, Type},
errors::CheckError, errors::CheckError,
prelude_compile::{parse, Config, Source}, prelude_compile::{parse, Config, Source},
program::parsed::CompInfo, program::parsed::CompInfo,
@ -25,11 +25,17 @@ fn show(src: String) {
eprintln!("{src}"); eprintln!("{src}");
match parse_compile_check_run(src) { match parse_compile_check_run(src) {
Err(e) => eprintln!("{e:?}"), Err(e) => eprintln!("{e:?}"),
Ok((t, v)) => eprintln!("Returned `{}` :: `{t}`", v.get()), Ok((t, v, i)) => eprintln!(
"Returned `{}` :: `{}`",
v.get().with_info(&i),
t.with_info(&i)
),
} }
} }
fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> { fn parse_compile_check_run(
src: String,
) -> Result<(Type, Data, mers_lib::program::run::Info), CheckError> {
// prepare the string for parsing // prepare the string for parsing
let mut source = Source::new_from_string(src); let mut source = Source::new_from_string(src);
// this is used for error messages // this is used for error messages
@ -47,5 +53,5 @@ fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
// check that the predicted output type was correct // check that the predicted output type was correct
assert!(output_value.get().as_type().is_included_in(&output_type)); assert!(output_value.get().as_type().is_included_in(&output_type));
// return the produced value // return the produced value
Ok((output_type, output_value)) Ok((output_type, output_value, i2))
} }

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Bool(pub bool); pub struct Bool(pub bool);
impl MersData for Bool { impl MersData for Bool {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -43,6 +48,13 @@ pub fn bool_type() -> Type {
Type::newm(vec![Arc::new(TrueT), Arc::new(FalseT)]) Type::newm(vec![Arc::new(TrueT), Arc::new(FalseT)])
} }
impl MersType for TrueT { impl MersType for TrueT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }
@ -63,6 +75,13 @@ impl MersType for TrueT {
} }
} }
impl MersType for FalseT { impl MersType for FalseT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Byte(pub u8); pub struct Byte(pub u8);
impl MersData for Byte { impl MersData for Byte {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Byte {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ByteT; pub struct ByteT;
impl MersType for ByteT { impl MersType for ByteT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }

View File

@ -28,7 +28,10 @@ pub fn assign(from: &Data, target: &Data) {
.as_any() .as_any()
.downcast_ref::<crate::data::object::Object>(), .downcast_ref::<crate::data::object::Object>(),
) { ) {
for ((_, from), (_, target)) in from.0.iter().zip(target.0.iter()) { for (field, target) in target.iter() {
let from = from
.get(*field)
.expect("type-checks should guarantee that from has every field of target");
assign(from, target); assign(from, target);
} }
} else { } else {

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Float(pub f64); pub struct Float(pub f64);
impl MersData for Float { impl MersData for Float {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Float {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FloatT; pub struct FloatT;
impl MersType for FloatT { impl MersType for FloatT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }

View File

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
errors::CheckError, errors::CheckError,
info::Local, info::DisplayInfo,
program::run::{CheckInfo, Info}, program::run::{CheckInfo, Info},
}; };
@ -87,13 +87,13 @@ impl Function {
(self.run)(arg, &mut self.info.duplicate()) (self.run)(arg, &mut self.info.duplicate())
} }
pub fn get_as_type(&self) -> FunctionT { pub fn get_as_type(&self) -> FunctionT {
let info = self.info_check.lock().unwrap().clone();
match &self.out { match &self.out {
Ok(out) => { Ok(out) => {
let out = Arc::clone(out); let out = Arc::clone(out);
let info = self.info_check.lock().unwrap().clone(); FunctionT(Ok(Arc::new(move |a, i| out(a, &mut i.clone()))), info)
FunctionT(Ok(Arc::new(move |a| out(a, &mut info.clone()))))
} }
Err(types) => FunctionT(Err(Arc::clone(types))), Err(types) => FunctionT(Err(Arc::clone(types)), info),
} }
} }
@ -108,6 +108,9 @@ impl Function {
} }
impl MersData for Function { impl MersData for Function {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
Some(self.get_as_type()) Some(self.get_as_type())
} }
@ -151,18 +154,50 @@ impl MersData for Function {
#[derive(Clone)] #[derive(Clone)]
pub struct FunctionT( pub struct FunctionT(
pub Result<Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>, Arc<Vec<(Type, Type)>>>, pub Result<
Arc<dyn Fn(&Type, &CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
Arc<Vec<(Type, Type)>>,
>,
pub CheckInfo,
); );
impl FunctionT { impl FunctionT {
/// get output type /// get output type
pub fn o(&self, i: &Type) -> Result<Type, CheckError> { pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
match &self.0 { match &self.0 {
Ok(f) => f(i), Ok(f) => f(i, &self.1),
Err(v) => v.iter().find(|(a, _)| i.is_included_in(a)).map(|(_, o)| o.clone()).ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {i}.").into()), Err(v) => v
.iter()
.find(|(a, _)| i.is_included_in(a))
.map(|(_, o)| o.clone())
.ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {}.", i.with_info(&self.1)).into()),
} }
} }
} }
impl MersType for FunctionT { impl MersType for FunctionT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
match &self.0 {
Err(e) => {
write!(f, "(")?;
for (index, (i, o)) in e.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{} -> {}", i.with_display(info), o.with_display(info))?;
}
write!(f, ")")
}
Ok(_) => match self.o(&Type::empty_tuple()) {
Ok(t) => write!(f, "(() -> {}, ...)", t.with_display(info)),
Err(_) => {
write!(f, "(... -> ...)",)
}
},
}
}
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
Some(self.clone()) Some(self.clone())
} }
@ -249,25 +284,3 @@ impl Display for Function {
write!(f, "<function>") write!(f, "<function>")
} }
} }
impl Display for FunctionT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
Err(e) => {
write!(f, "(")?;
for (index, (i, o)) in e.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{i} -> {o}")?;
}
write!(f, ")")
}
Ok(_) => match self.o(&Type::empty_tuple()) {
Ok(t) => write!(f, "(() -> {t}, ...)"),
Err(_) => {
write!(f, "(... -> ...)",)
}
},
}
}
}

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Int(pub isize); pub struct Int(pub isize);
impl MersData for Int { impl MersData for Int {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Int {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IntT; pub struct IntT;
impl MersType for IntT { impl MersType for IntT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }

View File

@ -4,7 +4,7 @@ use std::{
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
}; };
use crate::errors::CheckError; use crate::{errors::CheckError, info::DisplayInfo};
pub mod bool; pub mod bool;
pub mod byte; pub mod byte;
@ -18,7 +18,12 @@ pub mod tuple;
pub mod defs; pub mod defs;
pub trait MersData: Any + Debug + Display + Send + Sync { pub trait MersData: Any + Debug + Send + Sync {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result;
/// must be the same as the `executable` impl on the MersType /// must be the same as the `executable` impl on the MersType
#[allow(unused_variables)] #[allow(unused_variables)]
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
@ -46,7 +51,66 @@ pub trait MersData: Any + Debug + Display + Send + Sync {
fn to_any(self) -> Box<dyn Any>; fn to_any(self) -> Box<dyn Any>;
} }
pub trait MersType: Any + Debug + Display + Send + Sync { pub trait MersDataWInfo {
fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> MersDataWithInfo<'a, Self> {
MersDataWithInfo(self, *info)
}
fn with_info<'a>(
&'a self,
info: &'a crate::info::Info<impl crate::info::Local>,
) -> MersDataWithInfo<'a, Self> {
MersDataWithInfo(self, info.display_info())
}
}
pub trait MersTypeWInfo {
fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> MersTypeWithInfo<'a, Self> {
MersTypeWithInfo(self, *info)
}
fn with_info<'a>(
&'a self,
info: &'a crate::info::Info<impl crate::info::Local>,
) -> MersTypeWithInfo<'a, Self> {
MersTypeWithInfo(self, info.display_info())
}
}
impl Type {
pub fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> TypeWithInfo<'a> {
TypeWithInfo(self, *info)
}
pub fn with_info<'a>(
&'a self,
info: &'a crate::info::Info<impl crate::info::Local>,
) -> TypeWithInfo<'a> {
TypeWithInfo(self, info.display_info())
}
}
impl<T: MersData + ?Sized> MersDataWInfo for T {}
impl<T: MersType + ?Sized> MersTypeWInfo for T {}
pub struct MersDataWithInfo<'a, T: ?Sized>(&'a T, crate::info::DisplayInfo<'a>);
pub struct MersTypeWithInfo<'a, T: ?Sized>(&'a T, crate::info::DisplayInfo<'a>);
pub struct TypeWithInfo<'a>(&'a Type, crate::info::DisplayInfo<'a>);
impl<'a, T: ?Sized + MersData> Display for MersDataWithInfo<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.display(&self.1, f)
}
}
impl<'a, T: ?Sized + MersType> Display for MersTypeWithInfo<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.display(&self.1, f)
}
}
impl<'a> Display for TypeWithInfo<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.display(&self.1, f)
}
}
pub trait MersType: Any + Debug + Send + Sync {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result;
#[allow(unused_variables)] #[allow(unused_variables)]
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
None None
@ -93,13 +157,20 @@ pub trait MersType: Any + Debug + Display + Send + Sync {
} }
fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String { fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
self.simplify_for_display(info) self.simplify_for_display(info)
.map(|s| s.to_string()) .map(|s| s.with_info(info).to_string())
.unwrap_or_else(|| self.to_string()) .unwrap_or_else(|| self.with_info(info).to_string())
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct TypeWithOnlyName(pub(crate) String); pub(crate) struct TypeWithOnlyName(pub(crate) String);
impl MersType for TypeWithOnlyName { impl MersType for TypeWithOnlyName {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, _other: &dyn MersType) -> bool { fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
false false
} }
@ -447,20 +518,20 @@ impl Type {
out out
} }
pub fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String { pub fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
self.simplify_for_display(info).to_string() self.simplify_for_display(info).with_info(info).to_string()
} }
} }
impl Display for Type { impl Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn display(&self, info: &DisplayInfo, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.types.is_empty() { if self.types.is_empty() {
write!(f, "<unreachable>") write!(f, "<unreachable>")
} else { } else {
// if self.types.len() > 1 { // if self.types.len() > 1 {
// write!(f, "{{")?; // write!(f, "{{")?;
// } // }
write!(f, "{}", self.types[0])?; write!(f, "{}", self.types[0].with_display(info))?;
for t in self.types.iter().skip(1) { for t in self.types.iter().skip(1) {
write!(f, "/{t}")?; write!(f, "/{}", t.with_display(info))?;
} }
// if self.types.len() > 1 { // if self.types.len() > 1 {
// write!(f, "}}")?; // write!(f, "}}")?;

View File

@ -1,13 +1,61 @@
use std::{fmt::Display, sync::Arc}; use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use super::{Data, MersData, MersType, Type}; use crate::info::DisplayInfo;
use super::{Data, MersData, MersDataWInfo, MersType, Type};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Object(pub Vec<(String, Data)>); pub struct Object(Vec<(usize, Data)>);
impl Object {
pub fn new(v: Vec<(usize, Data)>) -> Self {
Self(v)
}
pub fn get(&self, f: usize) -> Option<&Data> {
self.iter().find(|v| v.0 == f).map(|v| &v.1)
}
pub fn iter(&self) -> std::slice::Iter<(usize, Data)> {
self.0.iter()
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ObjectT(pub Vec<(String, Type)>); pub struct ObjectT(Vec<(usize, Type)>);
impl ObjectT {
pub fn new(v: Vec<(usize, Type)>) -> Self {
Self(v)
}
pub fn get(&self, f: usize) -> Option<&Type> {
self.iter().find(|v| v.0 == f).map(|v| &v.1)
}
pub fn iter(&self) -> std::slice::Iter<(usize, Type)> {
self.0.iter()
}
fn len(&self) -> usize {
self.0.len()
}
}
impl MersData for Object { impl MersData for Object {
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut comma_sep = false;
write!(f, "{{")?;
for (field, val) in self.iter() {
if comma_sep {
write!(f, ", ")?;
}
write!(
f,
"{}: {}",
info.get_object_field_name(*field),
val.get().with_display(info)
)?;
comma_sep = true;
}
write!(f, "}}")?;
Ok(())
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
self == other self == other
@ -20,8 +68,7 @@ impl MersData for Object {
} }
fn as_type(&self) -> Type { fn as_type(&self) -> Type {
Type::new(ObjectT( Type::new(ObjectT(
self.0 self.iter()
.iter()
.map(|(n, v)| (n.clone(), v.get().as_type())) .map(|(n, v)| (n.clone(), v.get().as_type()))
.collect(), .collect(),
)) ))
@ -38,14 +85,35 @@ impl MersData for Object {
} }
impl MersType for ObjectT { impl MersType for ObjectT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
let mut comma_sep = false;
write!(f, "{{")?;
for (field, t) in self.iter() {
if comma_sep {
write!(f, ", ")?;
}
write!(
f,
"{}: {}",
info.get_object_field_name(*field),
t.with_display(info)
)?;
comma_sep = true;
}
write!(f, "}}")?;
Ok(())
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some_and(|other| { other.as_any().downcast_ref::<Self>().is_some_and(|other| {
self.0.len() == other.0.len() self.len() == other.len()
&& self && other.iter().all(|(field, target_type)| {
.0 self.get(*field)
.iter() .is_some_and(|self_type| self_type.is_same_type_as(target_type))
.zip(other.0.iter()) })
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_same_type_as(t2))
}) })
} }
fn is_included_in(&self, target: &dyn MersType) -> bool { fn is_included_in(&self, target: &dyn MersType) -> bool {
@ -53,16 +121,15 @@ impl MersType for ObjectT {
.as_any() .as_any()
.downcast_ref::<Self>() .downcast_ref::<Self>()
.is_some_and(|target| { .is_some_and(|target| {
self.0.len() >= target.0.len() self.len() >= target.len()
&& self && target.iter().all(|(field, target_type)| {
.0 self.get(*field)
.iter() .is_some_and(|self_type| self_type.is_included_in(target_type))
.zip(target.0.iter()) })
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_included_in(t2))
}) })
} }
fn subtypes(&self, acc: &mut Type) { fn subtypes(&self, acc: &mut Type) {
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.0.len())); self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.len()));
} }
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
self self
@ -83,44 +150,13 @@ impl MersType for ObjectT {
} }
} }
impl Display for Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut comma_sep = false;
write!(f, "{{")?;
for (name, val) in self.0.iter() {
if comma_sep {
write!(f, ", ")?;
}
write!(f, "{name}: {}", val.get())?;
comma_sep = true;
}
write!(f, "}}")?;
Ok(())
}
}
impl Display for ObjectT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut comma_sep = false;
write!(f, "{{")?;
for (name, t) in self.0.iter() {
if comma_sep {
write!(f, ", ")?;
}
write!(f, "{name}: {t}")?;
comma_sep = true;
}
write!(f, "}}")?;
Ok(())
}
}
impl ObjectT { impl ObjectT {
pub fn gen_subtypes_recursively( pub fn gen_subtypes_recursively(
&self, &self,
acc: &mut Type, acc: &mut Type,
types: &mut Vec<(String, Arc<dyn MersType>)>, types: &mut Vec<(usize, Arc<dyn MersType>)>,
) { ) {
if types.len() >= self.0.len() { if types.len() >= self.len() {
let nt = Self( let nt = Self(
types types
.iter() .iter()
@ -137,3 +173,18 @@ impl ObjectT {
} }
} }
} }
pub(crate) trait ObjectFieldsMap {
fn get_or_add_field(&self, field: &str) -> usize;
}
impl ObjectFieldsMap for Arc<Mutex<HashMap<String, usize>>> {
fn get_or_add_field(&self, field: &str) -> usize {
let mut s = self.lock().unwrap();
if let Some(f) = s.get(field) {
return *f;
}
let o = s.len();
s.insert(field.to_owned(), o);
o
}
}

View File

@ -1,10 +1,9 @@
use std::{ use std::{
any::Any, any::Any,
fmt::Display,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
use crate::errors::CheckError; use crate::{errors::CheckError, info::DisplayInfo};
use super::{Data, MersData, MersType, Type}; use super::{Data, MersData, MersType, Type};
@ -12,6 +11,9 @@ use super::{Data, MersData, MersType, Type};
pub struct Reference(pub Arc<RwLock<Data>>); pub struct Reference(pub Arc<RwLock<Data>>);
impl MersData for Reference { impl MersData for Reference {
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.0.read().unwrap().get().display(info, f)
}
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
let inner = self.0.read().unwrap(); let inner = self.0.read().unwrap();
let inner = inner.get(); let inner = inner.get();
@ -88,6 +90,17 @@ impl MersData for Reference {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReferenceT(pub Type); pub struct ReferenceT(pub Type);
impl MersType for ReferenceT { impl MersType for ReferenceT {
fn display(
&self,
info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
if self.0.types.len() > 1 {
write!(f, "&{{{}}}", self.0.with_display(info))
} else {
write!(f, "&{}", self.0.with_display(info))
}
}
fn executable(&self) -> Option<crate::data::function::FunctionT> { fn executable(&self) -> Option<crate::data::function::FunctionT> {
let mut funcs: Vec<crate::data::function::FunctionT> = vec![]; let mut funcs: Vec<crate::data::function::FunctionT> = vec![];
for func in self.0.types.iter() { for func in self.0.types.iter() {
@ -96,13 +109,16 @@ impl MersType for ReferenceT {
.downcast_ref::<crate::data::function::FunctionT>()?, .downcast_ref::<crate::data::function::FunctionT>()?,
)); ));
} }
Some(super::function::FunctionT(Ok(Arc::new(move |a| { Some(super::function::FunctionT(
let mut out = Type::empty(); Ok(Arc::new(move |a, _| {
for func in funcs.iter() { let mut out = Type::empty();
out.add_all(&func.o(a)?); for func in funcs.iter() {
} out.add_all(&func.o(a)?);
Ok(out) }
})))) Ok(out)
})),
crate::info::Info::neverused(),
))
} }
fn iterable(&self) -> Option<Type> { fn iterable(&self) -> Option<Type> {
let mut out = Type::empty(); let mut out = Type::empty();
@ -156,18 +172,3 @@ impl MersType for ReferenceT {
Some(&self.0) Some(&self.0)
} }
} }
impl Display for Reference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}", self.0.read().unwrap().get())
}
}
impl Display for ReferenceT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0.types.len() > 1 {
write!(f, "&{{{}}}", self.0)
} else {
write!(f, "&{}", self.0)
}
}
}

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct String(pub std::string::String); pub struct String(pub std::string::String);
impl MersData for String { impl MersData for String {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for String {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StringT; pub struct StringT;
impl MersType for StringT { impl MersType for StringT {
fn display(
&self,
_info: &crate::info::DisplayInfo<'_>,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{self}")
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
} }

View File

@ -1,6 +1,6 @@
use std::{any::Any, fmt::Display, sync::Arc}; use std::{any::Any, sync::Arc};
use crate::errors::CheckError; use crate::{errors::CheckError, info::DisplayInfo};
use super::{Data, MersData, MersType, Type}; use super::{Data, MersData, MersType, Type};
@ -17,6 +17,17 @@ impl Tuple {
} }
impl MersData for Tuple { impl MersData for Tuple {
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.get().display(info, f)?;
}
write!(f, ")")?;
Ok(())
}
fn is_eq(&self, other: &dyn MersData) -> bool { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0 other.0 == self.0
@ -47,6 +58,21 @@ impl MersData for Tuple {
#[derive(Debug)] #[derive(Debug)]
pub struct TupleT(pub Vec<Type>); pub struct TupleT(pub Vec<Type>);
impl MersType for TupleT { impl MersType for TupleT {
fn display(
&self,
info: &crate::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, ", ")?;
}
write!(f, "{}", c.with_display(info))?;
}
write!(f, ")")?;
Ok(())
}
fn iterable(&self) -> Option<Type> { fn iterable(&self) -> Option<Type> {
let mut o = Type::empty(); let mut o = Type::empty();
for t in self.0.iter() { for t in self.0.iter() {
@ -100,33 +126,6 @@ impl MersType for TupleT {
} }
} }
impl Display for Tuple {
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.get())?;
}
write!(f, ")")?;
Ok(())
}
}
impl Display for TupleT {
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)?;
}
write!(f, ")")?;
Ok(())
}
}
impl TupleT { impl TupleT {
pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) { pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) {
if types.len() >= self.0.len() { if types.len() >= self.0.len() {

View File

@ -83,6 +83,7 @@ pub enum EColor {
BadCharInFunctionType, BadCharInFunctionType,
BadCharAtStartOfStatement, BadCharAtStartOfStatement,
BadTypeFromParsed, BadTypeFromParsed,
ObjectDuplicateField,
TypeAnnotationNoClosingBracket, TypeAnnotationNoClosingBracket,
TryBadSyntax, TryBadSyntax,
TryNoFunctionFound, TryNoFunctionFound,

View File

@ -78,7 +78,7 @@ pub fn default_theme<C>(
TryBadSyntax => hard_err, TryBadSyntax => hard_err,
TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing, TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing,
BadTypeFromParsed => type_wrong_b, BadTypeFromParsed | ObjectDuplicateField => type_wrong_b,
// -- type-errors -- // -- type-errors --
IfConditionNotBool => type_wrong, IfConditionNotBool => type_wrong,

View File

@ -1,4 +1,8 @@
use std::fmt::Debug; use std::{
collections::HashMap,
fmt::{Debug, Display},
sync::{Arc, Mutex},
};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Info<L: Local> { pub struct Info<L: Local> {
@ -7,24 +11,68 @@ pub struct Info<L: Local> {
} }
impl<L: Local> Info<L> { impl<L: Local> Info<L> {
pub fn new(global: L::Global) -> Self {
Self {
scopes: vec![L::default()],
global,
}
}
/// Returns self, but completely empty (even without globals). /// Returns self, but completely empty (even without globals).
/// Only use this if you assume this Info will never be used. /// Only use this if you assume this Info will never be used.
pub fn neverused() -> Self { pub fn neverused() -> Self {
Self { Self::new(L::neverused_global())
scopes: vec![],
global: L::Global::default(),
}
} }
} }
pub trait Local: Default + Debug { pub trait Local: Default + Debug {
type VariableIdentifier; type VariableIdentifier;
type VariableData; type VariableData;
type Global: Default + Debug + Clone; type Global: Debug + Clone;
fn neverused_global() -> Self::Global;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData); fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>; fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>; fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
fn duplicate(&self) -> Self; fn duplicate(&self) -> Self;
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a>;
}
#[derive(Clone, Copy)]
pub struct DisplayInfo<'a> {
pub object_fields: &'a Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: &'a Arc<Mutex<Vec<String>>>,
}
pub struct GetObjectFieldNameDisplay<'a>(&'a DisplayInfo<'a>, usize);
impl<'a> Display for GetObjectFieldNameDisplay<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut object_fields_rev = self.0.object_fields_rev.lock().unwrap();
if self.1 < object_fields_rev.len() {
write!(f, "{}", object_fields_rev[self.1])
} else {
let object_fields = self.0.object_fields.lock().unwrap();
if self.1 < object_fields.len() {
let mut ofr = object_fields
.iter()
.map(|v| v.0.clone())
.collect::<Vec<_>>();
ofr.sort_by_cached_key(|v| object_fields.get(v).unwrap());
*object_fields_rev = ofr;
}
write!(
f,
"{}",
object_fields_rev
.get(self.1)
.map(String::as_str)
.unwrap_or("<UNKNOWN-OBJECT-FIELD>")
)
}
}
}
impl DisplayInfo<'_> {
/// this is almost always a constant-time operation, indexing a `Vec` with `field: usize`.
/// And even if it isn't, the second, third, ... time will be, so there is no need to cache the returned value.
pub fn get_object_field_name<'a>(&'a self, field: usize) -> GetObjectFieldNameDisplay<'a> {
GetObjectFieldNameDisplay(self, field)
}
} }
impl<L: Local> Info<L> { impl<L: Local> Info<L> {
@ -35,34 +83,26 @@ impl<L: Local> Info<L> {
pub fn end_scope(&mut self) { pub fn end_scope(&mut self) {
self.scopes.pop(); self.scopes.pop();
} }
pub fn display_info<'a>(&'a self) -> DisplayInfo<'a> {
L::display_info(&self.global)
}
} }
impl<L: Local> Local for Info<L> { impl<L: Local> Info<L> {
type VariableIdentifier = L::VariableIdentifier; pub fn init_var(&mut self, id: L::VariableIdentifier, value: L::VariableData) {
type VariableData = L::VariableData;
type Global = ();
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
self.scopes.last_mut().unwrap().init_var(id, value) self.scopes.last_mut().unwrap().init_var(id, value)
} }
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData> { pub fn get_var(&self, id: &L::VariableIdentifier) -> Option<&L::VariableData> {
self.scopes.iter().rev().find_map(|l| l.get_var(id)) self.scopes.iter().rev().find_map(|l| l.get_var(id))
} }
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData> { pub fn get_var_mut(&mut self, id: &L::VariableIdentifier) -> Option<&mut L::VariableData> {
self.scopes.iter_mut().rev().find_map(|l| l.get_var_mut(id)) self.scopes.iter_mut().rev().find_map(|l| l.get_var_mut(id))
} }
fn duplicate(&self) -> Self { pub fn duplicate(&self) -> Self {
Self { Self {
scopes: self.scopes.iter().map(|v| v.duplicate()).collect(), scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
global: self.global.clone(), global: self.global.clone(),
} }
} }
} }
impl<L: Local> Default for Info<L> {
fn default() -> Self {
Self {
scopes: vec![L::default()],
global: L::Global::default(),
}
}
}

View File

@ -358,11 +358,24 @@ pub fn parse_no_chain(
src.next_char(); src.next_char();
let pos_in_src_after_bracket = src.get_pos(); let pos_in_src_after_bracket = src.get_pos();
{ {
let mut elems = vec![]; let mut elems: Vec<(String, _)> = vec![];
loop { loop {
src.skip_whitespace(); src.skip_whitespace();
if src.peek_char() == Some('}') { if src.peek_char() == Some('}') {
src.next_char(); src.next_char();
for (i, a) in elems.iter().enumerate() {
if elems.iter().skip(1 + i).any(|b| a.0 == b.0) {
return Err(CheckError::new()
.src(vec![(
(pos_in_src, src.get_pos(), srca).into(),
Some(EColor::ObjectDuplicateField),
)])
.msg_str(format!(
"This object contains more than one field named `{}`",
a.0
)));
}
}
return Ok(Some(Box::new(program::parsed::object::Object { return Ok(Some(Box::new(program::parsed::object::Object {
pos_in_src: (pos_in_src, src.get_pos(), srca).into(), pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
elems, elems,

View File

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
data::{self, Type}, data::{self, object::ObjectFieldsMap, Type},
errors::{CheckError, EColor}, errors::{CheckError, EColor},
}; };
@ -173,6 +173,19 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
} }
} }
} }
for (i, a) in inner.iter().enumerate() {
if inner.iter().skip(1 + i).any(|b| a.0 == b.0) {
return Err(CheckError::new()
.src(vec![(
(pos_in_src, src.get_pos(), srca).into(),
Some(EColor::ObjectDuplicateField),
)])
.msg_str(format!(
"This object type contains more than one field named `{}`",
a.0
)));
}
}
ParsedType::Object(inner) ParsedType::Object(inner)
} }
Some(_) => { Some(_) => {
@ -239,20 +252,24 @@ pub fn type_from_parsed(
.map(|v| type_from_parsed(v, info)) .map(|v| type_from_parsed(v, info))
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
))), ))),
ParsedType::Object(o) => as_type.add(Arc::new(data::object::ObjectT( ParsedType::Object(o) => as_type.add(Arc::new(data::object::ObjectT::new(
o.iter() o.iter()
.map(|(s, v)| -> Result<_, CheckError> { .map(|(s, v)| -> Result<_, CheckError> {
Ok((s.clone(), type_from_parsed(v, info)?)) Ok((
info.global.object_fields.get_or_add_field(&s),
type_from_parsed(v, info)?,
))
}) })
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
))), ))),
ParsedType::Function(v) => { ParsedType::Function(v) => as_type.add(Arc::new(data::function::FunctionT(
as_type.add(Arc::new(data::function::FunctionT(Err(Arc::new( Err(Arc::new(
v.iter() v.iter()
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?))) .map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
.collect::<Result<_, CheckError>>()?, .collect::<Result<_, CheckError>>()?,
))))) )),
} info.clone(),
))),
ParsedType::Type(name) => match info ParsedType::Type(name) => match info
.scopes .scopes
.iter() .iter()
@ -274,7 +291,8 @@ pub fn type_from_parsed(
{ {
Some(Ok(t)) => { Some(Ok(t)) => {
return Err(CheckError::new().msg_str(format!( return Err(CheckError::new().msg_str(format!(
"Type: specified type with info, but type {t} doesn't need it" "Type: specified type with info, but type {} doesn't need it",
t.with_info(info)
))) )))
} }
Some(Err(f)) => as_type.add_all(&*f(&additional_info, info)?), Some(Err(f)) => as_type.add_all(&*f(&additional_info, info)?),

View File

@ -58,8 +58,12 @@ pub trait StaticMersFunc: Sized + 'static + Send + Sync {
Some(Err(e)) => Err(e), Some(Err(e)) => Err(e),
None => Err(CheckError::from(format!( None => Err(CheckError::from(format!(
"unexpected argument of type {}, expected {}", "unexpected argument of type {}, expected {}",
a.get().as_type(), a.get().as_type().with_info(i),
Type::new(data::function::FunctionT(Err(Arc::new(Self::types())))) 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}, data::{self, Data, MersData, Type},
errors::CheckError, errors::CheckError,
info::Local, info::Local,
program::run::CheckInfo, program::run::{CheckInfo, CheckLocalGlobalInfo, RunLocalGlobalInfo},
}; };
pub mod gen; pub mod gen;
@ -63,7 +63,15 @@ impl Config {
} }
pub fn new() -> Self { 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 { macro_rules! init_d {
($e:expr) => { ($e:expr) => {
let t = $e; let t = $e;
@ -89,8 +97,8 @@ impl Config {
init_d!(data::string::StringT); init_d!(data::string::StringT);
Self { Self {
globals: 0, globals: 0,
info_parsed: Default::default(), info_parsed,
info_run: Default::default(), info_run,
info_check, info_check,
} }
} }

View File

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

View File

@ -4,7 +4,7 @@ use std::{
}; };
use crate::{ use crate::{
data::{self, bool::bool_type, Data, Type}, data::{self, bool::bool_type, Data, MersTypeWInfo, Type},
errors::CheckError, errors::CheckError,
program::run::{CheckInfo, Info}, program::run::{CheckInfo, Info},
}; };
@ -30,7 +30,7 @@ impl Config {
.add_var("lock_update", data::function::Function { .add_var("lock_update", data::function::Function {
info: Info::neverused(), info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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() { for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() { if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() == 2 { if t.0.len() == 2 {
@ -42,23 +42,23 @@ impl Config {
match f.o(&arg) { match f.o(&arg) {
Ok(out) => { Ok(out) => {
if !out.is_included_in(&arg) { 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 { } else {
return Err(format!("Arguments must be (reference, function)").into()); return Err(format!("Arguments must be (reference, function)").into());
} }
} }
} else { } 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 { } 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 { } 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()) Ok(Type::empty_tuple())
@ -98,10 +98,10 @@ impl Config {
data::function::Function { data::function::Function {
info: Info::neverused(), info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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 { 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() { 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)) Ok(Type::new(data::int::IntT))
@ -174,7 +174,7 @@ impl Config {
data::function::Function { data::function::Function {
info: Info::neverused(), info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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| { run: Arc::new(|a, _i| {
if let Some(r) = a if let Some(r) = a

View File

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

View File

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

View File

@ -7,9 +7,10 @@ use crate::{
data::{ data::{
self, self,
function::{Function, FunctionT}, function::{Function, FunctionT},
Data, MersData, MersType, Type, Data, MersData, MersType, MersTypeWInfo, Type,
}, },
errors::CheckError, errors::CheckError,
info::DisplayInfo,
program::{self, run::CheckInfo}, program::{self, run::CheckInfo},
}; };
@ -49,7 +50,7 @@ impl Config {
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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 { for a in &a.types {
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() { 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)) { if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
@ -70,7 +71,8 @@ impl Config {
} }
} else { } else {
return Err(format!( 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" }, if v.iterable().is_some() { "iterable" } else { "not iterable" },
).into()); ).into());
} }
@ -133,13 +135,13 @@ impl Config {
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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() { let data = if let Some(a) = a.iterable() {
a a
} else { } 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())))), run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
inner_statements: None, inner_statements: None,
@ -150,13 +152,13 @@ impl Config {
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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() { let data = if let Some(a) = a.iterable() {
a a
} else { } 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())))), run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
inner_statements: None, inner_statements: None,
@ -172,6 +174,7 @@ fn genfunc_iter_and_func(
) -> data::function::Function { ) -> data::function::Function {
fn iter_out_arg( fn iter_out_arg(
a: &Type, a: &Type,
i: &mut CheckInfo,
name: &str, name: &str,
func: impl Fn(FunctionT) -> ItersT + Sync + Send, func: impl Fn(FunctionT) -> ItersT + Sync + Send,
) -> Result<Type, CheckError> { ) -> Result<Type, CheckError> {
@ -184,14 +187,16 @@ fn genfunc_iter_and_func(
if let Some(v) = t.0[0].iterable() { if let Some(v) = t.0[0].iterable() {
for f in t.0[1].types.iter() { for f in t.0[1].types.iter() {
if let Some(f) = f.executable() { 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 { } 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 { } else {
return Err(format!( 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()); .into());
} }
@ -202,7 +207,7 @@ fn genfunc_iter_and_func(
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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| { run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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(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 { ) -> data::function::Function {
fn iter_out_arg<T: MersType>( fn iter_out_arg<T: MersType>(
a: &Type, a: &Type,
i: &mut CheckInfo,
name: &str, name: &str,
func: impl Fn(&T) -> ItersT + Sync + Send, func: impl Fn(&T) -> ItersT + Sync + Send,
type_sample: &T, type_sample: &T,
) -> Result<Type, CheckError> { ) -> Result<Type, CheckError> {
let type_sample = type_sample.with_info(i);
let mut out = Type::empty(); let mut out = Type::empty();
for t in a.types.iter() { for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() { 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() { if let Some(v) = t.0[0].iterable() {
for f in t.0[1].types.iter() { for f in t.0[1].types.iter() {
if let Some(f) = f.as_any().downcast_ref::<T>() { 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 { } 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 { } else {
return Err(format!( 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()); .into());
} }
@ -256,8 +265,8 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(move |a, _i| { out: Ok(Arc::new(move |a, i| {
iter_out_arg(a, name, |f: &T| ft(f), type_sample) iter_out_arg(a, i, name, |f: &T| ft(f), type_sample)
})), })),
run: Arc::new(move |a, _i| { run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)] #[derive(Clone, Debug)]
pub struct IterT(pub ItersT, pub Type, pub Type); pub struct IterT(pub ItersT, pub Type, pub Type);
impl MersData for Iter { 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 { fn is_eq(&self, _other: &dyn MersData) -> bool {
false false
} }
@ -396,7 +408,14 @@ impl MersData for Iter {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_type(&self) -> data::Type { 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 { fn as_any(&self) -> &dyn std::any::Any {
self self
@ -409,7 +428,8 @@ impl MersData for Iter {
} }
} }
impl IterT { 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 { let t = match &iter {
ItersT::Map(f) => f.o(&data)?, ItersT::Map(f) => f.o(&data)?,
ItersT::Filter(f) => { ItersT::Filter(f) => {
@ -417,7 +437,8 @@ impl IterT {
data.clone() data.clone()
} else { } else {
return Err(format!( 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()); .into());
} }
@ -450,7 +471,8 @@ impl IterT {
out out
} else { } else {
return Err(format!( 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()); .into());
} }
@ -460,6 +482,13 @@ impl IterT {
} }
} }
impl MersType for 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 { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
self.2.is_same_type_as(&other.2) self.2.is_same_type_as(&other.2)
@ -496,11 +525,6 @@ impl Display for Iter {
write!(f, "<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 { impl Iters {
fn as_type(&self) -> ItersT { fn as_type(&self) -> ItersT {
match self { match self {
@ -527,15 +551,24 @@ fn genfunc_iter_in_val_out(
Function { Function {
info: crate::info::Info::neverused(), info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(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 let Some(iter_over) = a.iterable() {
if iter_over.is_included_in(&iter_type) { if iter_over.is_included_in(&iter_type) {
Ok(out_type.clone()) Ok(out_type.clone())
} else { } 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 { } 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), run: Arc::new(run),

View File

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

View File

@ -326,7 +326,7 @@ fn num_iter_to_num(
data::function::Function { data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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() { if let Some(a) = a.iterable() {
let int_type = Type::new(data::int::IntT); let int_type = Type::new(data::int::IntT);
if a.is_included_in(&int_type) { if a.is_included_in(&int_type) {
@ -343,7 +343,7 @@ fn num_iter_to_num(
if a.is_included_in(&int_float_type) { if a.is_included_in(&int_float_type) {
Ok(int_float_type) Ok(int_float_type)
} else { } 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::{ use crate::{
data::{self, Data, MersData, MersType, Type}, data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
errors::CheckError, errors::CheckError,
info::DisplayInfo,
parsing::{statements::to_string_literal, Source}, parsing::{statements::to_string_literal, Source},
program::{self, run::CheckInfo}, program::{self, run::CheckInfo},
}; };
@ -57,10 +58,10 @@ impl Config {
.add_var("thread_finished", data::function::Function { .add_var("thread_finished", data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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() { for t in a.types.iter() {
if !t.as_any().is::<ThreadT>() { 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()) Ok(data::bool::bool_type())
@ -78,13 +79,13 @@ impl Config {
.add_var("thread_await", data::function::Function { .add_var("thread_await", data::function::Function {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::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(); let mut out = Type::empty();
for t in a.types.iter() { for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ThreadT>() { if let Some(t) = t.as_any().downcast_ref::<ThreadT>() {
out.add_all(&t.0); out.add_all(&t.0);
} else { } 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) Ok(out)
@ -112,6 +113,9 @@ pub struct Thread(
pub struct ThreadT(pub Type); pub struct ThreadT(pub Type);
impl MersData for Thread { 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 { fn is_eq(&self, _other: &dyn MersData) -> bool {
false false
} }
@ -132,6 +136,17 @@ impl MersData for Thread {
} }
} }
impl MersType for ThreadT { 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 { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
self.0.is_same_type_as(&other.0) self.0.is_same_type_as(&other.0)
@ -172,8 +187,3 @@ impl Display for Thread {
write!(f, "<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::{ use crate::{
data::{self, Data, Type}, data::{self, Data, MersDataWInfo, Type},
program::{self, run::CheckInfo}, program::{self, run::CheckInfo},
}; };
@ -66,9 +66,9 @@ impl Config {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|a, _i| Ok(a.clone()))), out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
run: Arc::new(|a, _i| { run: Arc::new(|a, i| {
let a2 = a.get(); let a2 = a.get();
eprintln!("{} :: {}", a2.as_type(), a2); eprintln!("{} :: {}", a2.as_type().with_info(i), a2.with_info(i));
drop(a2); drop(a2);
Ok(a) Ok(a)
}), }),
@ -81,8 +81,8 @@ impl Config {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| { run: Arc::new(|a, i| {
eprint!("{}", a.get()); eprint!("{}", a.get().with_info(i));
_ = std::io::stderr().lock().flush(); _ = std::io::stderr().lock().flush();
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
@ -95,8 +95,8 @@ impl Config {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| { run: Arc::new(|a, i| {
eprintln!("{}", a.get()); eprintln!("{}", a.get().with_info(i));
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,
@ -108,8 +108,8 @@ impl Config {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| { run: Arc::new(|a, i| {
print!("{}", a.get()); print!("{}", a.get().with_info(i));
_ = std::io::stdout().lock().flush(); _ = std::io::stdout().lock().flush();
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
@ -122,8 +122,8 @@ impl Config {
info: program::run::Info::neverused(), info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| { run: Arc::new(|a, i| {
println!("{}", a.get()); println!("{}", a.get().with_info(i));
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,

View File

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

View File

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

View File

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
errors::{CheckError, SourceRange}, errors::{CheckError, SourceRange},
info, info::{self, DisplayInfo},
}; };
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
@ -113,7 +113,7 @@ pub struct Local {
pub vars: HashMap<String, (usize, usize)>, pub vars: HashMap<String, (usize, usize)>,
pub vars_count: usize, pub vars_count: usize,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug)]
pub struct LocalGlobalInfo { pub struct LocalGlobalInfo {
pub depth: usize, pub depth: usize,
pub enable_hooks: bool, 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 { impl info::Local for Local {
type VariableIdentifier = String; type VariableIdentifier = String;
type VariableData = (usize, usize); type VariableData = (usize, usize);
type Global = LocalGlobalInfo; 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) { fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
self.vars_count += 1; self.vars_count += 1;
self.vars.insert(id, value); self.vars.insert(id, value);
@ -147,4 +169,10 @@ impl info::Local for Local {
fn duplicate(&self) -> Self { fn duplicate(&self) -> Self {
self.clone() 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::{ use crate::{
data::object::ObjectFieldsMap,
errors::{CheckError, SourceRange}, errors::{CheckError, SourceRange},
info, info, program,
program::{self},
}; };
use super::{CompInfo, MersStatement}; use super::{CompInfo, MersStatement};
@ -22,10 +22,15 @@ impl MersStatement for Object {
) -> Result<Box<dyn program::run::MersStatement>, CheckError> { ) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
Ok(Box::new(program::run::object::Object { Ok(Box::new(program::run::object::Object {
pos_in_src: self.pos_in_src.clone(), pos_in_src: self.pos_in_src.clone(),
elems: self fields: self
.elems .elems
.iter() .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<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
})) }))
} }

View File

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

View File

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

View File

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
data::{self, Data, Type}, data::{self, Data, MersTypeWInfo, Type},
errors::{CheckError, SourceRange}, errors::{CheckError, SourceRange},
}; };
@ -28,7 +28,7 @@ impl MersStatement for Loop {
if let Some(i) = i.as_any().downcast_ref::<data::tuple::TupleT>() { if let Some(i) = i.as_any().downcast_ref::<data::tuple::TupleT>() {
if i.0.len() > 1 { if i.0.len() > 1 {
return Err(format!( 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()); .into());
} else { } else {
@ -40,7 +40,7 @@ impl MersStatement for Loop {
} }
} else { } else {
return Err(format!( 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()); .into());
} }

View File

@ -8,7 +8,7 @@ use std::{
use crate::{ use crate::{
data::{self, Data, Type}, data::{self, Data, Type},
errors::{CheckError, EColor, SourceRange}, errors::{CheckError, EColor, SourceRange},
info, info::{self, DisplayInfo},
}; };
#[cfg(feature = "run")] #[cfg(feature = "run")]
@ -126,10 +126,21 @@ pub type CheckInfo = info::Info<CheckLocal>;
pub struct RunLocal { pub struct RunLocal {
pub vars: Vec<Arc<RwLock<Data>>>, pub vars: Vec<Arc<RwLock<Data>>>,
} }
#[derive(Default, Clone, Debug)] #[derive(Clone, Debug)]
pub struct RunLocalGlobalInfo { pub struct RunLocalGlobalInfo {
/// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error. /// 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 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)] #[derive(Default, Clone)]
pub struct CheckLocal { pub struct CheckLocal {
@ -142,7 +153,7 @@ pub struct CheckLocal {
>, >,
>, >,
} }
#[derive(Clone, Default)] #[derive(Clone)]
pub struct CheckLocalGlobalInfo { pub struct CheckLocalGlobalInfo {
pub depth: usize, pub depth: usize,
pub enable_hooks: bool, pub enable_hooks: bool,
@ -160,6 +171,8 @@ pub struct CheckLocalGlobalInfo {
>, >,
>, >,
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>, 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 { impl CheckLocalGlobalInfo {
pub fn show_warnings_to_stderr(&mut self) { pub fn show_warnings_to_stderr(&mut self) {
@ -171,6 +184,18 @@ impl CheckLocalGlobalInfo {
eprintln!("{}", e.display(theme)); 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 { impl Debug for CheckLocalGlobalInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -186,6 +211,13 @@ impl info::Local for RunLocal {
type VariableIdentifier = usize; type VariableIdentifier = usize;
type VariableData = Arc<RwLock<Data>>; type VariableData = Arc<RwLock<Data>>;
type Global = RunLocalGlobalInfo; 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) { fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false)))); let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
while self.vars.len() <= id { while self.vars.len() <= id {
@ -214,11 +246,28 @@ impl info::Local for RunLocal {
.collect(), .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 { impl info::Local for CheckLocal {
type VariableIdentifier = usize; type VariableIdentifier = usize;
type VariableData = Type; type VariableData = Type;
type Global = CheckLocalGlobalInfo; 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) { fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
while self.vars.len() <= id { while self.vars.len() <= id {
self.vars.push(Type::empty()); self.vars.push(Type::empty());
@ -240,4 +289,10 @@ impl info::Local for CheckLocal {
fn duplicate(&self) -> Self { fn duplicate(&self) -> Self {
self.clone() 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::{ use crate::{
data::{self, object::ObjectT, Data, MersType, Type}, data::{self, object::ObjectT, Data, Type},
errors::{CheckError, EColor, SourceRange}, errors::{CheckError, EColor, SourceRange},
}; };
@ -10,7 +10,7 @@ use super::MersStatement;
#[derive(Debug)] #[derive(Debug)]
pub struct Object { pub struct Object {
pub pos_in_src: SourceRange, pub pos_in_src: SourceRange,
pub elems: Vec<(String, Box<dyn MersStatement>)>, pub fields: Vec<(usize, Box<dyn MersStatement>)>,
} }
impl MersStatement for Object { impl MersStatement for Object {
fn check_custom( fn check_custom(
@ -18,75 +18,16 @@ impl MersStatement for Object {
info: &mut super::CheckInfo, info: &mut super::CheckInfo,
init_to: Option<&Type>, init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> { ) -> Result<data::Type, super::CheckError> {
let mut assign_types = if let Some(init_to) = init_to { let mut init_fields = if let Some(init_to) = init_to {
let mut acc = (0..self.elems.len())
.map(|_| Type::empty())
.collect::<VecDeque<_>>();
let print_is_part_of = init_to.types.len() > 1; let print_is_part_of = init_to.types.len() > 1;
let mut init_fields = HashMap::new();
for t in init_to.types.iter() { for t in init_to.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() { if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
if self.elems.len() == t.0.len() { for (field, t) in t.iter() {
for (i, ((sn, _), (tn, t))) in self.elems.iter().zip(t.0.iter()).enumerate() init_fields
{ .entry(*field)
if sn != tn { .or_insert_with(Type::empty)
return Err(CheckError::new().msg(vec![ .add_all(t);
("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)
]));
} }
} else { } else {
return Err(CheckError::new().msg(vec![ return Err(CheckError::new().msg(vec![
@ -111,20 +52,39 @@ impl MersStatement for Object {
])); ]));
} }
} }
Some(acc) Some(init_fields)
} else { } else {
None None
}; };
Ok(Type::new(data::object::ObjectT( Ok(Type::new(data::object::ObjectT::new(
self.elems self.fields
.iter() .iter()
.map(|(n, v)| -> Result<_, CheckError> { .map(|(field, v)| -> Result<_, CheckError> {
Ok(( Ok((
n.clone(), *field,
v.check( v.check(
info, info,
if let Some(it) = &mut assign_types { if let Some(f) = &mut init_fields {
Some(it.pop_front().unwrap()) 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 { } else {
None None
} }
@ -136,8 +96,8 @@ impl MersStatement for Object {
))) )))
} }
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> { fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(Data::new(data::object::Object( Ok(Data::new(data::object::Object::new(
self.elems self.fields
.iter() .iter()
.map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?))) .map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?)))
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
@ -150,7 +110,7 @@ impl MersStatement for Object {
self.pos_in_src.clone() self.pos_in_src.clone()
} }
fn inner_statements(&self) -> Vec<&dyn MersStatement> { 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 { fn as_any(&self) -> &dyn std::any::Any {
self self

View File

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

View File

@ -1,5 +1,6 @@
use std::{fmt::Debug, sync::Arc}; use std::{fmt::Debug, sync::Arc};
use mers_lib::data::MersDataWInfo;
use mers_lib::prelude_compile::*; use mers_lib::prelude_compile::*;
use mers_lib::{ use mers_lib::{
@ -15,7 +16,8 @@ fn variable() -> Res {
run_code(Config::new(), format!("x := {n}, x"))?, run_code(Config::new(), format!("x := {n}, x"))?,
TypedData( TypedData(
Type::new(data::int::IntT), Type::new(data::int::IntT),
Data::new(data::int::Int(n as _)) Data::new(data::int::Int(n as _)),
mers_lib::info::Info::neverused(),
) )
); );
} }
@ -26,7 +28,11 @@ fn variable() -> Res {
fn mutating_a_variable() -> Res { fn mutating_a_variable() -> Res {
assert_eq!( assert_eq!(
run_code(Config::new(), "x := 5, &x = 2, x")?, run_code(Config::new(), "x := 5, &x = 2, x")?,
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(2))) TypedData(
Type::new(data::int::IntT),
Data::new(data::int::Int(2)),
mers_lib::info::Info::neverused()
),
); );
Ok(()) Ok(())
} }
@ -35,7 +41,11 @@ fn mutating_a_variable() -> Res {
fn variable_shadowing() -> Res { fn variable_shadowing() -> Res {
assert_eq!( assert_eq!(
run_code(Config::new(), "x := 5, { x := 2, &x = 3 }, x")?, run_code(Config::new(), "x := 5, { x := 2, &x = 3 }, x")?,
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(5))) TypedData(
Type::new(data::int::IntT),
Data::new(data::int::Int(5)),
mers_lib::info::Info::neverused()
)
); );
Ok(()) Ok(())
} }
@ -44,7 +54,11 @@ fn variable_shadowing() -> Res {
fn identity_function() -> Res { fn identity_function() -> Res {
assert_eq!( assert_eq!(
run_code(Config::new(), "id := x -> x, 4.id")?, run_code(Config::new(), "id := x -> x, 4.id")?,
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(4))) TypedData(
Type::new(data::int::IntT),
Data::new(data::int::Int(4)),
mers_lib::info::Info::neverused()
)
); );
Ok(()) Ok(())
} }
@ -59,13 +73,18 @@ fn run_code(cfg: Config, code: impl Into<String>) -> Result<TypedData, CheckErro
let compiled = parsed.compile(&mut i1, Default::default())?; let compiled = parsed.compile(&mut i1, Default::default())?;
let output_type = compiled.check(&mut i3, Default::default())?; let output_type = compiled.check(&mut i3, Default::default())?;
let output_data = compiled.run(&mut i2)?; let output_data = compiled.run(&mut i2)?;
Ok(TypedData(output_type, output_data)) Ok(TypedData(output_type, output_data, i2))
} }
struct TypedData(Type, Data); struct TypedData(Type, Data, mers_lib::program::run::Info);
impl Debug for TypedData { impl Debug for TypedData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Type: {}, Data: {}", self.0, self.1.get()) write!(
f,
"Type: {}, Data: {}",
self.0.with_info(&self.2),
self.1.get().with_info(&self.2)
)
} }
} }
impl PartialEq for TypedData { impl PartialEq for TypedData {
@ -75,16 +94,16 @@ impl PartialEq for TypedData {
let d1 = self.1 == other.1; let d1 = self.1 == other.1;
let d2 = other.1 == self.1; let d2 = other.1 == self.1;
if t1 && !t2 { if t1 && !t2 {
panic!("self is same type as other, but other is not same type as self (non-symmetrical eq)! self={}, other={}", self.0, other.0); panic!("self is same type as other, but other is not same type as self (non-symmetrical eq)! self={}, other={}", self.0.with_info(&self.2), other.0.with_info(&self.2));
} }
if t2 && !t1 { if t2 && !t1 {
panic!("other is same type as self, but self is not same type as other (non-symmetrical eq)! other={}, self={}", other.0, self.0); panic!("other is same type as self, but self is not same type as other (non-symmetrical eq)! other={}, self={}", other.0.with_info(&self.2), self.0.with_info(&self.2));
} }
if d1 && !d2 { if d1 && !d2 {
panic!("self is same data as other, but other is not same data as self (non-symmetrical eq)! self={}, other={}", self.1.get(), other.1.get()); panic!("self is same data as other, but other is not same data as self (non-symmetrical eq)! self={}, other={}", self.1.get().with_info(&self.2), other.1.get().with_info(&self.2));
} }
if d2 && !d1 { if d2 && !d1 {
panic!("other is same data as self, but self is not same data as other (non-symmetrical eq)! other={}, self={}", other.1.get(), self.1.get()); panic!("other is same data as self, but self is not same data as other (non-symmetrical eq)! other={}, self={}", other.1.get().with_info(&self.2), self.1.get().with_info(&self.2));
} }
t1 && d1 t1 && d1
} }