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"]
[dependencies]
mers_lib = "0.9.2"
# mers_lib = { path = "../mers_lib" }
# mers_lib = "0.9.2"
mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true }

View File

@ -132,12 +132,12 @@ fn main() {
eprintln!("{e:?}");
exit(24);
}
Ok(compiled) => match check(&*compiled, i3) {
Ok(compiled) => match check_mut(&*compiled, &mut i3) {
Err(e) => {
eprintln!("{e:?}");
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 mers_lib::{
data::{Data, Type},
data::{Data, MersDataWInfo, Type},
errors::CheckError,
prelude_compile::{parse, Config, Source},
program::parsed::CompInfo,
@ -25,11 +25,17 @@ fn show(src: String) {
eprintln!("{src}");
match parse_compile_check_run(src) {
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
let mut source = Source::new_from_string(src);
// 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
assert!(output_value.get().as_type().is_included_in(&output_type));
// 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 crate::info::DisplayInfo;
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Bool(pub 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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -43,6 +48,13 @@ pub fn bool_type() -> Type {
Type::newm(vec![Arc::new(TrueT), Arc::new(FalseT)])
}
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 {
other.as_any().downcast_ref::<Self>().is_some()
}
@ -63,6 +75,13 @@ impl MersType for TrueT {
}
}
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 {
other.as_any().downcast_ref::<Self>().is_some()
}

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type};
#[derive(Debug, Clone, Copy)]
pub struct Byte(pub u8);
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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Byte {
#[derive(Debug, Clone)]
pub struct 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 {
other.as_any().downcast_ref::<Self>().is_some()
}

View File

@ -28,7 +28,10 @@ pub fn assign(from: &Data, target: &Data) {
.as_any()
.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);
}
} else {

View File

@ -1,11 +1,16 @@
use std::{any::Any, fmt::Display, sync::Arc};
use crate::info::DisplayInfo;
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Float(pub f64);
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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Float {
#[derive(Debug, Clone)]
pub struct 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 {
other.as_any().downcast_ref::<Self>().is_some()
}

View File

@ -6,7 +6,7 @@ use std::{
use crate::{
errors::CheckError,
info::Local,
info::DisplayInfo,
program::run::{CheckInfo, Info},
};
@ -87,13 +87,13 @@ impl Function {
(self.run)(arg, &mut self.info.duplicate())
}
pub fn get_as_type(&self) -> FunctionT {
let info = self.info_check.lock().unwrap().clone();
match &self.out {
Ok(out) => {
let out = Arc::clone(out);
let info = self.info_check.lock().unwrap().clone();
FunctionT(Ok(Arc::new(move |a| out(a, &mut info.clone()))))
FunctionT(Ok(Arc::new(move |a, i| out(a, &mut i.clone()))), info)
}
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 {
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self}")
}
fn executable(&self) -> Option<crate::data::function::FunctionT> {
Some(self.get_as_type())
}
@ -151,18 +154,50 @@ impl MersData for Function {
#[derive(Clone)]
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 {
/// get output type
pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
match &self.0 {
Ok(f) => f(i),
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()),
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.with_info(&self.1)).into()),
}
}
}
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> {
Some(self.clone())
}
@ -249,25 +284,3 @@ impl Display for 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 crate::info::DisplayInfo;
use super::{MersData, MersType, Type};
#[derive(Debug, Clone, Copy)]
pub struct Int(pub isize);
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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for Int {
#[derive(Debug, Clone)]
pub struct 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 {
other.as_any().downcast_ref::<Self>().is_some()
}

View File

@ -4,7 +4,7 @@ use std::{
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use crate::errors::CheckError;
use crate::{errors::CheckError, info::DisplayInfo};
pub mod bool;
pub mod byte;
@ -18,7 +18,12 @@ pub mod tuple;
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
#[allow(unused_variables)]
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>;
}
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)]
fn executable(&self) -> Option<crate::data::function::FunctionT> {
None
@ -93,13 +157,20 @@ pub trait MersType: Any + Debug + Display + Send + Sync {
}
fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
self.simplify_for_display(info)
.map(|s| s.to_string())
.unwrap_or_else(|| self.to_string())
.map(|s| s.with_info(info).to_string())
.unwrap_or_else(|| self.with_info(info).to_string())
}
}
#[derive(Clone, Debug)]
pub(crate) struct TypeWithOnlyName(pub(crate) String);
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 {
false
}
@ -447,20 +518,20 @@ impl Type {
out
}
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 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Type {
fn display(&self, info: &DisplayInfo, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.types.is_empty() {
write!(f, "<unreachable>")
} else {
// if self.types.len() > 1 {
// write!(f, "{{")?;
// }
write!(f, "{}", self.types[0])?;
write!(f, "{}", self.types[0].with_display(info))?;
for t in self.types.iter().skip(1) {
write!(f, "/{t}")?;
write!(f, "/{}", t.with_display(info))?;
}
// if self.types.len() > 1 {
// 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)]
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)]
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 {
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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
self == other
@ -20,8 +68,7 @@ impl MersData for Object {
}
fn as_type(&self) -> Type {
Type::new(ObjectT(
self.0
.iter()
self.iter()
.map(|(n, v)| (n.clone(), v.get().as_type()))
.collect(),
))
@ -38,14 +85,35 @@ impl MersData for Object {
}
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 {
other.as_any().downcast_ref::<Self>().is_some_and(|other| {
self.0.len() == other.0.len()
&& self
.0
.iter()
.zip(other.0.iter())
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_same_type_as(t2))
self.len() == other.len()
&& other.iter().all(|(field, target_type)| {
self.get(*field)
.is_some_and(|self_type| self_type.is_same_type_as(target_type))
})
})
}
fn is_included_in(&self, target: &dyn MersType) -> bool {
@ -53,16 +121,15 @@ impl MersType for ObjectT {
.as_any()
.downcast_ref::<Self>()
.is_some_and(|target| {
self.0.len() >= target.0.len()
&& self
.0
.iter()
.zip(target.0.iter())
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_included_in(t2))
self.len() >= target.len()
&& target.iter().all(|(field, target_type)| {
self.get(*field)
.is_some_and(|self_type| self_type.is_included_in(target_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 {
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 {
pub fn gen_subtypes_recursively(
&self,
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(
types
.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::{
any::Any,
fmt::Display,
sync::{Arc, RwLock},
};
use crate::errors::CheckError;
use crate::{errors::CheckError, info::DisplayInfo};
use super::{Data, MersData, MersType, Type};
@ -12,6 +11,9 @@ use super::{Data, MersData, MersType, Type};
pub struct Reference(pub Arc<RwLock<Data>>);
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> {
let inner = self.0.read().unwrap();
let inner = inner.get();
@ -88,6 +90,17 @@ impl MersData for Reference {
#[derive(Debug, Clone)]
pub struct ReferenceT(pub Type);
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> {
let mut funcs: Vec<crate::data::function::FunctionT> = vec![];
for func in self.0.types.iter() {
@ -96,13 +109,16 @@ impl MersType for ReferenceT {
.downcast_ref::<crate::data::function::FunctionT>()?,
));
}
Some(super::function::FunctionT(Ok(Arc::new(move |a| {
Some(super::function::FunctionT(
Ok(Arc::new(move |a, _| {
let mut out = Type::empty();
for func in funcs.iter() {
out.add_all(&func.o(a)?);
}
Ok(out)
}))))
})),
crate::info::Info::neverused(),
))
}
fn iterable(&self) -> Option<Type> {
let mut out = Type::empty();
@ -156,18 +172,3 @@ impl MersType for ReferenceT {
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 crate::info::DisplayInfo;
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct String(pub std::string::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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -33,6 +38,13 @@ impl MersData for String {
#[derive(Debug, Clone)]
pub struct 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 {
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};
@ -17,6 +17,17 @@ impl 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 {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
@ -47,6 +58,21 @@ impl MersData for Tuple {
#[derive(Debug)]
pub struct TupleT(pub Vec<Type>);
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> {
let mut o = Type::empty();
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 {
pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) {
if types.len() >= self.0.len() {

View File

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

View File

@ -78,7 +78,7 @@ pub fn default_theme<C>(
TryBadSyntax => hard_err,
TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing,
BadTypeFromParsed => type_wrong_b,
BadTypeFromParsed | ObjectDuplicateField => type_wrong_b,
// -- type-errors --
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)]
pub struct Info<L: Local> {
@ -7,24 +11,68 @@ pub struct Info<L: Local> {
}
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).
/// Only use this if you assume this Info will never be used.
pub fn neverused() -> Self {
Self {
scopes: vec![],
global: L::Global::default(),
}
Self::new(L::neverused_global())
}
}
pub trait Local: Default + Debug {
type VariableIdentifier;
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 get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
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> {
@ -35,34 +83,26 @@ impl<L: Local> Info<L> {
pub fn end_scope(&mut self) {
self.scopes.pop();
}
pub fn display_info<'a>(&'a self) -> DisplayInfo<'a> {
L::display_info(&self.global)
}
}
impl<L: Local> Local for Info<L> {
type VariableIdentifier = L::VariableIdentifier;
type VariableData = L::VariableData;
type Global = ();
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
impl<L: Local> Info<L> {
pub fn init_var(&mut self, id: L::VariableIdentifier, value: L::VariableData) {
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))
}
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))
}
fn duplicate(&self) -> Self {
pub fn duplicate(&self) -> Self {
Self {
scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
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();
let pos_in_src_after_bracket = src.get_pos();
{
let mut elems = vec![];
let mut elems: Vec<(String, _)> = vec![];
loop {
src.skip_whitespace();
if src.peek_char() == Some('}') {
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 {
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
elems,

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::{
data::{self, Type},
data::{self, object::ObjectFieldsMap, Type},
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)
}
Some(_) => {
@ -239,20 +252,24 @@ pub fn type_from_parsed(
.map(|v| type_from_parsed(v, info))
.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()
.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<_, _>>()?,
))),
ParsedType::Function(v) => {
as_type.add(Arc::new(data::function::FunctionT(Err(Arc::new(
ParsedType::Function(v) => as_type.add(Arc::new(data::function::FunctionT(
Err(Arc::new(
v.iter()
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
.collect::<Result<_, CheckError>>()?,
)))))
}
)),
info.clone(),
))),
ParsedType::Type(name) => match info
.scopes
.iter()
@ -274,7 +291,8 @@ pub fn type_from_parsed(
{
Some(Ok(t)) => {
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)?),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
use std::{fmt::Debug, sync::Arc};
use mers_lib::data::MersDataWInfo;
use mers_lib::prelude_compile::*;
use mers_lib::{
@ -15,7 +16,8 @@ fn variable() -> Res {
run_code(Config::new(), format!("x := {n}, x"))?,
TypedData(
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 {
assert_eq!(
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(())
}
@ -35,7 +41,11 @@ fn mutating_a_variable() -> Res {
fn variable_shadowing() -> Res {
assert_eq!(
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(())
}
@ -44,7 +54,11 @@ fn variable_shadowing() -> Res {
fn identity_function() -> Res {
assert_eq!(
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(())
}
@ -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 output_type = compiled.check(&mut i3, Default::default())?;
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 {
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 {
@ -75,16 +94,16 @@ impl PartialEq for TypedData {
let d1 = self.1 == other.1;
let d2 = other.1 == self.1;
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 {
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 {
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 {
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
}