From c17ea580b25eec3b8bdc76c003299079adec3981 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Sat, 28 Sep 2024 01:51:20 +0200 Subject: [PATCH] make objects work better, especially destructuring --- mers/Cargo.toml | 4 +- mers/src/main.rs | 4 +- .../examples/00_parse_compile_check_run.rs | 14 +- mers_lib/src/data/bool.rs | 19 +++ mers_lib/src/data/byte.rs | 12 ++ mers_lib/src/data/defs.rs | 5 +- mers_lib/src/data/float.rs | 12 ++ mers_lib/src/data/function.rs | 71 ++++---- mers_lib/src/data/int.rs | 12 ++ mers_lib/src/data/mod.rs | 91 ++++++++-- mers_lib/src/data/object.rs | 155 ++++++++++++------ mers_lib/src/data/reference.rs | 49 +++--- mers_lib/src/data/string.rs | 12 ++ mers_lib/src/data/tuple.rs | 57 ++++--- mers_lib/src/errors/mod.rs | 1 + mers_lib/src/errors/themes.rs | 2 +- mers_lib/src/info/mod.rs | 86 +++++++--- mers_lib/src/parsing/statements.rs | 15 +- mers_lib/src/parsing/types.rs | 34 +++- mers_lib/src/program/configs/gen/function.rs | 8 +- mers_lib/src/program/configs/mod.rs | 16 +- mers_lib/src/program/configs/util.rs | 46 ++++-- mers_lib/src/program/configs/with_base.rs | 20 +-- .../program/configs/with_command_running.rs | 65 +++++--- mers_lib/src/program/configs/with_get.rs | 14 +- mers_lib/src/program/configs/with_iters.rs | 93 +++++++---- mers_lib/src/program/configs/with_list.rs | 77 ++++----- mers_lib/src/program/configs/with_math.rs | 4 +- .../program/configs/with_multithreading.rs | 30 ++-- mers_lib/src/program/configs/with_stdio.rs | 22 +-- mers_lib/src/program/configs/with_string.rs | 21 ++- mers_lib/src/program/parsed/include_mers.rs | 4 +- mers_lib/src/program/parsed/mod.rs | 32 +++- mers_lib/src/program/parsed/object.rs | 13 +- mers_lib/src/program/parsed/variable.rs | 3 +- mers_lib/src/program/run/function.rs | 1 - mers_lib/src/program/run/loop.rs | 6 +- mers_lib/src/program/run/mod.rs | 61 ++++++- mers_lib/src/program/run/object.rs | 118 +++++-------- mers_lib/src/program/run/try.rs | 2 +- mers_lib/tests/lang.rs | 41 +++-- 41 files changed, 899 insertions(+), 453 deletions(-) diff --git a/mers/Cargo.toml b/mers/Cargo.toml index 56b276e..ac1b698 100644 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -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 } diff --git a/mers/src/main.rs b/mers/src/main.rs index 69853b8..e617b32 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -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)), }, } } diff --git a/mers_lib/examples/00_parse_compile_check_run.rs b/mers_lib/examples/00_parse_compile_check_run.rs index 8d14052..23c408e 100644 --- a/mers_lib/examples/00_parse_compile_check_run.rs +++ b/mers_lib/examples/00_parse_compile_check_run.rs @@ -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)) } diff --git a/mers_lib/src/data/bool.rs b/mers_lib/src/data/bool.rs index 2734969..f859ae7 100755 --- a/mers_lib/src/data/bool.rs +++ b/mers_lib/src/data/bool.rs @@ -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::() { 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::().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::().is_some() } diff --git a/mers_lib/src/data/byte.rs b/mers_lib/src/data/byte.rs index 213ea4a..01ceca9 100644 --- a/mers_lib/src/data/byte.rs +++ b/mers_lib/src/data/byte.rs @@ -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::() { 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::().is_some() } diff --git a/mers_lib/src/data/defs.rs b/mers_lib/src/data/defs.rs index 0a91b9e..ebbe160 100755 --- a/mers_lib/src/data/defs.rs +++ b/mers_lib/src/data/defs.rs @@ -28,7 +28,10 @@ pub fn assign(from: &Data, target: &Data) { .as_any() .downcast_ref::(), ) { - 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 { diff --git a/mers_lib/src/data/float.rs b/mers_lib/src/data/float.rs index 3b1a8e4..073440e 100755 --- a/mers_lib/src/data/float.rs +++ b/mers_lib/src/data/float.rs @@ -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::() { 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::().is_some() } diff --git a/mers_lib/src/data/function.rs b/mers_lib/src/data/function.rs index 768d44c..5efcc5d 100755 --- a/mers_lib/src/data/function.rs +++ b/mers_lib/src/data/function.rs @@ -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 { Some(self.get_as_type()) } @@ -151,18 +154,50 @@ impl MersData for Function { #[derive(Clone)] pub struct FunctionT( - pub Result Result + Send + Sync>, Arc>>, + pub Result< + Arc Result + Send + Sync>, + Arc>, + >, + pub CheckInfo, ); impl FunctionT { /// get output type pub fn o(&self, i: &Type) -> Result { 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 { Some(self.clone()) } @@ -249,25 +284,3 @@ impl Display for Function { write!(f, "") } } -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, "(... -> ...)",) - } - }, - } - } -} diff --git a/mers_lib/src/data/int.rs b/mers_lib/src/data/int.rs index e1008a2..2d72e14 100755 --- a/mers_lib/src/data/int.rs +++ b/mers_lib/src/data/int.rs @@ -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::() { 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::().is_some() } diff --git a/mers_lib/src/data/mod.rs b/mers_lib/src/data/mod.rs index 4f0d421..aa2795e 100755 --- a/mers_lib/src/data/mod.rs +++ b/mers_lib/src/data/mod.rs @@ -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 { @@ -46,7 +51,66 @@ pub trait MersData: Any + Debug + Display + Send + Sync { fn to_any(self) -> Box; } -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, + ) -> 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, + ) -> 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, + ) -> TypeWithInfo<'a> { + TypeWithInfo(self, info.display_info()) + } +} +impl MersDataWInfo for T {} +impl 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 { 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, "") } 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, "}}")?; diff --git a/mers_lib/src/data/object.rs b/mers_lib/src/data/object.rs index 10e0139..9aa4508 100644 --- a/mers_lib/src/data/object.rs +++ b/mers_lib/src/data/object.rs @@ -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 == 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::().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::() .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)>, + types: &mut Vec<(usize, Arc)>, ) { - 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>> { + 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 + } +} diff --git a/mers_lib/src/data/reference.rs b/mers_lib/src/data/reference.rs index 59fcb31..6d554b8 100755 --- a/mers_lib/src/data/reference.rs +++ b/mers_lib/src/data/reference.rs @@ -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>); 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 { 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 { let mut funcs: Vec = vec![]; for func in self.0.types.iter() { @@ -96,13 +109,16 @@ impl MersType for ReferenceT { .downcast_ref::()?, )); } - Some(super::function::FunctionT(Ok(Arc::new(move |a| { - let mut out = Type::empty(); - for func in funcs.iter() { - out.add_all(&func.o(a)?); - } - Ok(out) - })))) + 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 { 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) - } - } -} diff --git a/mers_lib/src/data/string.rs b/mers_lib/src/data/string.rs index 0207a77..1adebdc 100755 --- a/mers_lib/src/data/string.rs +++ b/mers_lib/src/data/string.rs @@ -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::() { 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::().is_some() } diff --git a/mers_lib/src/data/tuple.rs b/mers_lib/src/data/tuple.rs index 353b831..348dd9b 100755 --- a/mers_lib/src/data/tuple.rs +++ b/mers_lib/src/data/tuple.rs @@ -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::() { other.0 == self.0 @@ -47,6 +58,21 @@ impl MersData for Tuple { #[derive(Debug)] pub struct TupleT(pub Vec); 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 { 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>) { if types.len() >= self.0.len() { diff --git a/mers_lib/src/errors/mod.rs b/mers_lib/src/errors/mod.rs index 0ff07e0..2c63331 100644 --- a/mers_lib/src/errors/mod.rs +++ b/mers_lib/src/errors/mod.rs @@ -83,6 +83,7 @@ pub enum EColor { BadCharInFunctionType, BadCharAtStartOfStatement, BadTypeFromParsed, + ObjectDuplicateField, TypeAnnotationNoClosingBracket, TryBadSyntax, TryNoFunctionFound, diff --git a/mers_lib/src/errors/themes.rs b/mers_lib/src/errors/themes.rs index 8e7ded5..ca65d2d 100644 --- a/mers_lib/src/errors/themes.rs +++ b/mers_lib/src/errors/themes.rs @@ -78,7 +78,7 @@ pub fn default_theme( TryBadSyntax => hard_err, TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing, - BadTypeFromParsed => type_wrong_b, + BadTypeFromParsed | ObjectDuplicateField => type_wrong_b, // -- type-errors -- IfConditionNotBool => type_wrong, diff --git a/mers_lib/src/info/mod.rs b/mers_lib/src/info/mod.rs index cae5e14..5a969b4 100755 --- a/mers_lib/src/info/mod.rs +++ b/mers_lib/src/info/mod.rs @@ -1,4 +1,8 @@ -use std::fmt::Debug; +use std::{ + collections::HashMap, + fmt::{Debug, Display}, + sync::{Arc, Mutex}, +}; #[derive(Clone, Debug)] pub struct Info { @@ -7,24 +11,68 @@ pub struct Info { } impl Info { + 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>>, + pub object_fields_rev: &'a Arc>>, +} +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::>(); + 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("") + ) + } + } +} +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 Info { @@ -35,34 +83,26 @@ impl Info { pub fn end_scope(&mut self) { self.scopes.pop(); } + + pub fn display_info<'a>(&'a self) -> DisplayInfo<'a> { + L::display_info(&self.global) + } } -impl Local for Info { - type VariableIdentifier = L::VariableIdentifier; - type VariableData = L::VariableData; - type Global = (); - fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) { +impl Info { + 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 Default for Info { - fn default() -> Self { - Self { - scopes: vec![L::default()], - global: L::Global::default(), - } - } -} diff --git a/mers_lib/src/parsing/statements.rs b/mers_lib/src/parsing/statements.rs index bca8a10..1307869 100755 --- a/mers_lib/src/parsing/statements.rs +++ b/mers_lib/src/parsing/statements.rs @@ -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, diff --git a/mers_lib/src/parsing/types.rs b/mers_lib/src/parsing/types.rs index 46b6d9d..64a96d7 100755 --- a/mers_lib/src/parsing/types.rs +++ b/mers_lib/src/parsing/types.rs @@ -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) -> Result { @@ -239,20 +252,24 @@ pub fn type_from_parsed( .map(|v| type_from_parsed(v, info)) .collect::>()?, ))), - 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::>()?, ))), - 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::>()?, - ))))) - } + )), + 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)?), diff --git a/mers_lib/src/program/configs/gen/function.rs b/mers_lib/src/program/configs/gen/function.rs index 945d30d..4335bc2 100644 --- a/mers_lib/src/program/configs/gen/function.rs +++ b/mers_lib/src/program/configs/gen/function.rs @@ -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) ))), } }) diff --git a/mers_lib/src/program/configs/mod.rs b/mers_lib/src/program/configs/mod.rs index 962d00e..741d911 100755 --- a/mers_lib/src/program/configs/mod.rs +++ b/mers_lib/src/program/configs/mod.rs @@ -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, } } diff --git a/mers_lib/src/program/configs/util.rs b/mers_lib/src/program/configs/util.rs index 630e604..9745d69 100644 --- a/mers_lib/src/program/configs/util.rs +++ b/mers_lib/src/program/configs/util.rs @@ -7,29 +7,46 @@ use crate::{ }; pub fn to_mers_func( - out: impl Fn(&Type) -> Result + Send + Sync + 'static, - run: impl Fn(Data) -> Result + Send + Sync + 'static, + out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result + + Send + + Sync + + 'static, + run: impl Fn(Data, &mut crate::program::run::Info) -> Result + + 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 + Send + Sync + 'static, - run: impl Fn(Data) -> Result + Send + Sync + 'static, + out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result + + Send + + Sync + + 'static, + run: impl Fn(Data, &mut crate::program::run::Info) -> Result + + 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 + Send + Sync + 'static, + run: impl Fn(Data, &mut crate::program::run::Info) -> Result + + 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 + 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::() @@ -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::().unwrap().0; let l = a[0].get(); diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index fe3387b..06ec6e8 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -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::() { 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::().is_none() && t.as_any().downcast_ref::().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 diff --git a/mers_lib/src/program/configs/with_command_running.rs b/mers_lib/src/program/configs/with_command_running.rs index 108ecb5..4596f9a 100755 --- a/mers_lib/src/program/configs/with_command_running.rs +++ b/mers_lib/src/program/configs/with_command_running.rs @@ -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::().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))").into()); } })), - run: Arc::new(|a, _i| { + run: Arc::new(|a, i| { let a = a.get(); let cmd = a.as_any().downcast_ref::().unwrap(); let (cmd, args) = (&cmd.0[0], &cmd.0[1]); @@ -52,7 +53,7 @@ impl Config { cmd.as_any().downcast_ref::().unwrap(), args.get().iterable().unwrap(), ); - let args = args.map(|v| v.map(|v| v.get().to_string())).collect::, _>>()?; + let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::, _>>()?; 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::().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))").into()); } })), - run: Arc::new(|a, _i| { + run: Arc::new(|a, i| { let a = a.get(); let cmd = a.as_any().downcast_ref::().unwrap(); let (cmd, args) = (&cmd.0[0], &cmd.0[1]); @@ -103,7 +104,7 @@ impl Config { cmd.as_any().downcast_ref::().unwrap(), args.get().iterable().unwrap(), ); - let args = args.map(|v| v.map(|v| v.get().to_string())).collect::, _>>()?; + let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::, _>>()?; 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::().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)` type {a}").into()); + return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter)` 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>>> { 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 { None } diff --git a/mers_lib/src/program/configs/with_get.rs b/mers_lib/src/program/configs/with_get.rs index a190d79..d11c1f5 100755 --- a/mers_lib/src/program/configs/with_get.rs +++ b/mers_lib/src/program/configs/with_get.rs @@ -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::() { @@ -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![ diff --git a/mers_lib/src/program/configs/with_iters.rs b/mers_lib/src/program/configs/with_iters.rs index faa92df..b1b8301 100755 --- a/mers_lib/src/program/configs/with_iters.rs +++ b/mers_lib/src/program/configs/with_iters.rs @@ -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::() { 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 { @@ -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::() { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) { @@ -225,10 +230,12 @@ fn genfunc_iter_and_arg( ) -> data::function::Function { fn iter_out_arg( a: &Type, + i: &mut CheckInfo, name: &str, func: impl Fn(&T) -> ItersT + Sync + Send, type_sample: &T, ) -> Result { + 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::() { @@ -238,14 +245,16 @@ fn genfunc_iter_and_arg( if let Some(v) = t.0[0].iterable() { for f in t.0[1].types.iter() { if let Some(f) = f.as_any().downcast_ref::() { - out.add(Arc::new(IterT::new(func(f), v.clone())?)); + 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( 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::() { @@ -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 { + /// `i` is only used for errors (this is important for `as_type()`) + pub fn new(iter: ItersT, data: Type, i: &CheckInfo) -> Result { 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, "", 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.2.is_same_type_as(&other.2) @@ -496,11 +525,6 @@ impl Display for Iter { write!(f, "") } } -impl Display for IterT { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "", 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), diff --git a/mers_lib/src/program/configs/with_list.rs b/mers_lib/src/program/configs/with_list.rs index 9f246e3..6a6b05d 100755 --- a/mers_lib/src/program/configs/with_list.rs +++ b/mers_lib/src/program/configs/with_list.rs @@ -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::() { @@ -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::() { if t.0.len() != 2 { @@ -166,22 +164,22 @@ impl Config { if let Some(t) = t.as_any().downcast_ref::() { 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::() { 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 { 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(); diff --git a/mers_lib/src/program/configs/with_math.rs b/mers_lib/src/program/configs/with_math.rs index 1d54675..fa902ad 100755 --- a/mers_lib/src/program/configs/with_math.rs +++ b/mers_lib/src/program/configs/with_math.rs @@ -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()) } } } diff --git a/mers_lib/src/program/configs/with_multithreading.rs b/mers_lib/src/program/configs/with_multithreading.rs index b2cc41d..ef45270 100755 --- a/mers_lib/src/program/configs/with_multithreading.rs +++ b/mers_lib/src/program/configs/with_multithreading.rs @@ -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::() { - 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::() { 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.0.is_same_type_as(&other.0) @@ -172,8 +187,3 @@ impl Display for Thread { write!(f, "") } } -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(), '>')) - } -} diff --git a/mers_lib/src/program/configs/with_stdio.rs b/mers_lib/src/program/configs/with_stdio.rs index 9e53e46..935f1a4 100755 --- a/mers_lib/src/program/configs/with_stdio.rs +++ b/mers_lib/src/program/configs/with_stdio.rs @@ -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, diff --git a/mers_lib/src/program/configs/with_string.rs b/mers_lib/src/program/configs/with_string.rs index 2bd61e0..69b7d35 100755 --- a/mers_lib/src/program/configs/with_string.rs +++ b/mers_lib/src/program/configs/with_string.rs @@ -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::>()?, ))) }, @@ -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( diff --git a/mers_lib/src/program/parsed/include_mers.rs b/mers_lib/src/program/parsed/include_mers.rs index 170a629..8a43079 100644 --- a/mers_lib/src/program/parsed/include_mers.rs +++ b/mers_lib/src/program/parsed/include_mers.rs @@ -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}; diff --git a/mers_lib/src/program/parsed/mod.rs b/mers_lib/src/program/parsed/mod.rs index 433d914..48cf6e9 100755 --- a/mers_lib/src/program/parsed/mod.rs +++ b/mers_lib/src/program/parsed/mod.rs @@ -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, 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>>, + pub object_fields_rev: Arc>>, +} +impl LocalGlobalInfo { + pub fn new(object_fields: Arc>>) -> 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, + } + } } diff --git a/mers_lib/src/program/parsed/object.rs b/mers_lib/src/program/parsed/object.rs index 5d717b1..f89b349 100644 --- a/mers_lib/src/program/parsed/object.rs +++ b/mers_lib/src/program/parsed/object.rs @@ -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, 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::, _>>()?, })) } diff --git a/mers_lib/src/program/parsed/variable.rs b/mers_lib/src/program/parsed/variable.rs index ae9e735..0c336ed 100755 --- a/mers_lib/src/program/parsed/variable.rs +++ b/mers_lib/src/program/parsed/variable.rs @@ -1,7 +1,6 @@ use crate::{ errors::{CheckError, EColor, SourceRange}, - info::Local, - program::{self}, + program, }; use super::{CompInfo, MersStatement}; diff --git a/mers_lib/src/program/run/function.rs b/mers_lib/src/program/run/function.rs index 61fea62..aae7417 100755 --- a/mers_lib/src/program/run/function.rs +++ b/mers_lib/src/program/run/function.rs @@ -1,7 +1,6 @@ use crate::{ data::{self, Data, MersData, Type}, errors::{CheckError, SourceRange}, - info::Local, }; use super::MersStatement; diff --git a/mers_lib/src/program/run/loop.rs b/mers_lib/src/program/run/loop.rs index 8b1befe..5474d99 100644 --- a/mers_lib/src/program/run/loop.rs +++ b/mers_lib/src/program/run/loop.rs @@ -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::() { 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()); } diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 91e6ceb..9861209 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -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; pub struct RunLocal { pub vars: Vec>>, } -#[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, + pub object_fields: Arc>>, + pub object_fields_rev: Arc>>, +} +impl RunLocalGlobalInfo { + pub fn new(object_fields: Arc>>) -> 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>)>>>, + pub object_fields: Arc>>, + pub object_fields_rev: Arc>>, } 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>>) -> 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>; 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, + } + } } diff --git a/mers_lib/src/program/run/object.rs b/mers_lib/src/program/run/object.rs index 8204f96..3852ced 100644 --- a/mers_lib/src/program/run/object.rs +++ b/mers_lib/src/program/run/object.rs @@ -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)>, + pub fields: Vec<(usize, Box)>, } impl MersStatement for Object { fn check_custom( @@ -18,75 +18,16 @@ impl MersStatement for Object { info: &mut super::CheckInfo, init_to: Option<&Type>, ) -> Result { - let mut assign_types = if let Some(init_to) = init_to { - let mut acc = (0..self.elems.len()) - .map(|_| Type::empty()) - .collect::>(); + 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::() { - 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::(), - 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 { - 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::>()?, @@ -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 diff --git a/mers_lib/src/program/run/try.rs b/mers_lib/src/program/run/try.rs index bcc5dbc..26a932a 100644 --- a/mers_lib/src/program/run/try.rs +++ b/mers_lib/src/program/run/try.rs @@ -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), diff --git a/mers_lib/tests/lang.rs b/mers_lib/tests/lang.rs index 705db94..cf5aad2 100644 --- a/mers_lib/tests/lang.rs +++ b/mers_lib/tests/lang.rs @@ -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) -> Result) -> 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 }