mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
make objects work better, especially destructuring
This commit is contained in:
parent
9c8e918440
commit
c17ea580b2
@ -15,7 +15,7 @@ default = ["colored-output"]
|
|||||||
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
|
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mers_lib = "0.9.2"
|
# mers_lib = "0.9.2"
|
||||||
# mers_lib = { path = "../mers_lib" }
|
mers_lib = { path = "../mers_lib" }
|
||||||
clap = { version = "4.3.19", features = ["derive"] }
|
clap = { version = "4.3.19", features = ["derive"] }
|
||||||
colored = { version = "2.1.0", optional = true }
|
colored = { version = "2.1.0", optional = true }
|
||||||
|
@ -132,12 +132,12 @@ fn main() {
|
|||||||
eprintln!("{e:?}");
|
eprintln!("{e:?}");
|
||||||
exit(24);
|
exit(24);
|
||||||
}
|
}
|
||||||
Ok(compiled) => match check(&*compiled, i3) {
|
Ok(compiled) => match check_mut(&*compiled, &mut i3) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e:?}");
|
eprintln!("{e:?}");
|
||||||
exit(28);
|
exit(28);
|
||||||
}
|
}
|
||||||
Ok(output_type) => eprintln!("{output_type}"),
|
Ok(output_type) => eprintln!("{}", output_type.with_info(&i3)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mers_lib::{
|
use mers_lib::{
|
||||||
data::{Data, Type},
|
data::{Data, MersDataWInfo, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
prelude_compile::{parse, Config, Source},
|
prelude_compile::{parse, Config, Source},
|
||||||
program::parsed::CompInfo,
|
program::parsed::CompInfo,
|
||||||
@ -25,11 +25,17 @@ fn show(src: String) {
|
|||||||
eprintln!("{src}");
|
eprintln!("{src}");
|
||||||
match parse_compile_check_run(src) {
|
match parse_compile_check_run(src) {
|
||||||
Err(e) => eprintln!("{e:?}"),
|
Err(e) => eprintln!("{e:?}"),
|
||||||
Ok((t, v)) => eprintln!("Returned `{}` :: `{t}`", v.get()),
|
Ok((t, v, i)) => eprintln!(
|
||||||
|
"Returned `{}` :: `{}`",
|
||||||
|
v.get().with_info(&i),
|
||||||
|
t.with_info(&i)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
|
fn parse_compile_check_run(
|
||||||
|
src: String,
|
||||||
|
) -> Result<(Type, Data, mers_lib::program::run::Info), CheckError> {
|
||||||
// prepare the string for parsing
|
// prepare the string for parsing
|
||||||
let mut source = Source::new_from_string(src);
|
let mut source = Source::new_from_string(src);
|
||||||
// this is used for error messages
|
// this is used for error messages
|
||||||
@ -47,5 +53,5 @@ fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
|
|||||||
// check that the predicted output type was correct
|
// check that the predicted output type was correct
|
||||||
assert!(output_value.get().as_type().is_included_in(&output_type));
|
assert!(output_value.get().as_type().is_included_in(&output_type));
|
||||||
// return the produced value
|
// return the produced value
|
||||||
Ok((output_type, output_value))
|
Ok((output_type, output_value, i2))
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
use super::{MersData, MersType, Type};
|
use super::{MersData, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Bool(pub bool);
|
pub struct Bool(pub bool);
|
||||||
|
|
||||||
impl MersData for Bool {
|
impl MersData for Bool {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -43,6 +48,13 @@ pub fn bool_type() -> Type {
|
|||||||
Type::newm(vec![Arc::new(TrueT), Arc::new(FalseT)])
|
Type::newm(vec![Arc::new(TrueT), Arc::new(FalseT)])
|
||||||
}
|
}
|
||||||
impl MersType for TrueT {
|
impl MersType for TrueT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
@ -63,6 +75,13 @@ impl MersType for TrueT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for FalseT {
|
impl MersType for FalseT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
use super::{MersData, MersType, Type};
|
use super::{MersData, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Byte(pub u8);
|
pub struct Byte(pub u8);
|
||||||
|
|
||||||
impl MersData for Byte {
|
impl MersData for Byte {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -33,6 +38,13 @@ impl MersData for Byte {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ByteT;
|
pub struct ByteT;
|
||||||
impl MersType for ByteT {
|
impl MersType for ByteT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,10 @@ pub fn assign(from: &Data, target: &Data) {
|
|||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::data::object::Object>(),
|
.downcast_ref::<crate::data::object::Object>(),
|
||||||
) {
|
) {
|
||||||
for ((_, from), (_, target)) in from.0.iter().zip(target.0.iter()) {
|
for (field, target) in target.iter() {
|
||||||
|
let from = from
|
||||||
|
.get(*field)
|
||||||
|
.expect("type-checks should guarantee that from has every field of target");
|
||||||
assign(from, target);
|
assign(from, target);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
use super::{MersData, MersType, Type};
|
use super::{MersData, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Float(pub f64);
|
pub struct Float(pub f64);
|
||||||
|
|
||||||
impl MersData for Float {
|
impl MersData for Float {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -33,6 +38,13 @@ impl MersData for Float {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FloatT;
|
pub struct FloatT;
|
||||||
impl MersType for FloatT {
|
impl MersType for FloatT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
info::Local,
|
info::DisplayInfo,
|
||||||
program::run::{CheckInfo, Info},
|
program::run::{CheckInfo, Info},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,13 +87,13 @@ impl Function {
|
|||||||
(self.run)(arg, &mut self.info.duplicate())
|
(self.run)(arg, &mut self.info.duplicate())
|
||||||
}
|
}
|
||||||
pub fn get_as_type(&self) -> FunctionT {
|
pub fn get_as_type(&self) -> FunctionT {
|
||||||
|
let info = self.info_check.lock().unwrap().clone();
|
||||||
match &self.out {
|
match &self.out {
|
||||||
Ok(out) => {
|
Ok(out) => {
|
||||||
let out = Arc::clone(out);
|
let out = Arc::clone(out);
|
||||||
let info = self.info_check.lock().unwrap().clone();
|
FunctionT(Ok(Arc::new(move |a, i| out(a, &mut i.clone()))), info)
|
||||||
FunctionT(Ok(Arc::new(move |a| out(a, &mut info.clone()))))
|
|
||||||
}
|
}
|
||||||
Err(types) => FunctionT(Err(Arc::clone(types))),
|
Err(types) => FunctionT(Err(Arc::clone(types)), info),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +108,9 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MersData for Function {
|
impl MersData for Function {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
Some(self.get_as_type())
|
Some(self.get_as_type())
|
||||||
}
|
}
|
||||||
@ -151,18 +154,50 @@ impl MersData for Function {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FunctionT(
|
pub struct FunctionT(
|
||||||
pub Result<Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>, Arc<Vec<(Type, Type)>>>,
|
pub Result<
|
||||||
|
Arc<dyn Fn(&Type, &CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
|
||||||
|
Arc<Vec<(Type, Type)>>,
|
||||||
|
>,
|
||||||
|
pub CheckInfo,
|
||||||
);
|
);
|
||||||
impl FunctionT {
|
impl FunctionT {
|
||||||
/// get output type
|
/// get output type
|
||||||
pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
|
pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Ok(f) => f(i),
|
Ok(f) => f(i, &self.1),
|
||||||
Err(v) => v.iter().find(|(a, _)| i.is_included_in(a)).map(|(_, o)| o.clone()).ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {i}.").into()),
|
Err(v) => v
|
||||||
|
.iter()
|
||||||
|
.find(|(a, _)| i.is_included_in(a))
|
||||||
|
.map(|(_, o)| o.clone())
|
||||||
|
.ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {}.", i.with_info(&self.1)).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for FunctionT {
|
impl MersType for FunctionT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
match &self.0 {
|
||||||
|
Err(e) => {
|
||||||
|
write!(f, "(")?;
|
||||||
|
for (index, (i, o)) in e.iter().enumerate() {
|
||||||
|
if index > 0 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{} -> {}", i.with_display(info), o.with_display(info))?;
|
||||||
|
}
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
Ok(_) => match self.o(&Type::empty_tuple()) {
|
||||||
|
Ok(t) => write!(f, "(() -> {}, ...)", t.with_display(info)),
|
||||||
|
Err(_) => {
|
||||||
|
write!(f, "(... -> ...)",)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
Some(self.clone())
|
Some(self.clone())
|
||||||
}
|
}
|
||||||
@ -249,25 +284,3 @@ impl Display for Function {
|
|||||||
write!(f, "<function>")
|
write!(f, "<function>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for FunctionT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match &self.0 {
|
|
||||||
Err(e) => {
|
|
||||||
write!(f, "(")?;
|
|
||||||
for (index, (i, o)) in e.iter().enumerate() {
|
|
||||||
if index > 0 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{i} -> {o}")?;
|
|
||||||
}
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
Ok(_) => match self.o(&Type::empty_tuple()) {
|
|
||||||
Ok(t) => write!(f, "(() -> {t}, ...)"),
|
|
||||||
Err(_) => {
|
|
||||||
write!(f, "(... -> ...)",)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
use super::{MersData, MersType, Type};
|
use super::{MersData, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Int(pub isize);
|
pub struct Int(pub isize);
|
||||||
|
|
||||||
impl MersData for Int {
|
impl MersData for Int {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -33,6 +38,13 @@ impl MersData for Int {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IntT;
|
pub struct IntT;
|
||||||
impl MersType for IntT {
|
impl MersType for IntT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::errors::CheckError;
|
use crate::{errors::CheckError, info::DisplayInfo};
|
||||||
|
|
||||||
pub mod bool;
|
pub mod bool;
|
||||||
pub mod byte;
|
pub mod byte;
|
||||||
@ -18,7 +18,12 @@ pub mod tuple;
|
|||||||
|
|
||||||
pub mod defs;
|
pub mod defs;
|
||||||
|
|
||||||
pub trait MersData: Any + Debug + Display + Send + Sync {
|
pub trait MersData: Any + Debug + Send + Sync {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result;
|
||||||
/// must be the same as the `executable` impl on the MersType
|
/// must be the same as the `executable` impl on the MersType
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
@ -46,7 +51,66 @@ pub trait MersData: Any + Debug + Display + Send + Sync {
|
|||||||
fn to_any(self) -> Box<dyn Any>;
|
fn to_any(self) -> Box<dyn Any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MersType: Any + Debug + Display + Send + Sync {
|
pub trait MersDataWInfo {
|
||||||
|
fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> MersDataWithInfo<'a, Self> {
|
||||||
|
MersDataWithInfo(self, *info)
|
||||||
|
}
|
||||||
|
fn with_info<'a>(
|
||||||
|
&'a self,
|
||||||
|
info: &'a crate::info::Info<impl crate::info::Local>,
|
||||||
|
) -> MersDataWithInfo<'a, Self> {
|
||||||
|
MersDataWithInfo(self, info.display_info())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait MersTypeWInfo {
|
||||||
|
fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> MersTypeWithInfo<'a, Self> {
|
||||||
|
MersTypeWithInfo(self, *info)
|
||||||
|
}
|
||||||
|
fn with_info<'a>(
|
||||||
|
&'a self,
|
||||||
|
info: &'a crate::info::Info<impl crate::info::Local>,
|
||||||
|
) -> MersTypeWithInfo<'a, Self> {
|
||||||
|
MersTypeWithInfo(self, info.display_info())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Type {
|
||||||
|
pub fn with_display<'a>(&'a self, info: &DisplayInfo<'a>) -> TypeWithInfo<'a> {
|
||||||
|
TypeWithInfo(self, *info)
|
||||||
|
}
|
||||||
|
pub fn with_info<'a>(
|
||||||
|
&'a self,
|
||||||
|
info: &'a crate::info::Info<impl crate::info::Local>,
|
||||||
|
) -> TypeWithInfo<'a> {
|
||||||
|
TypeWithInfo(self, info.display_info())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: MersData + ?Sized> MersDataWInfo for T {}
|
||||||
|
impl<T: MersType + ?Sized> MersTypeWInfo for T {}
|
||||||
|
pub struct MersDataWithInfo<'a, T: ?Sized>(&'a T, crate::info::DisplayInfo<'a>);
|
||||||
|
pub struct MersTypeWithInfo<'a, T: ?Sized>(&'a T, crate::info::DisplayInfo<'a>);
|
||||||
|
pub struct TypeWithInfo<'a>(&'a Type, crate::info::DisplayInfo<'a>);
|
||||||
|
impl<'a, T: ?Sized + MersData> Display for MersDataWithInfo<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.display(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T: ?Sized + MersType> Display for MersTypeWithInfo<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.display(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> Display for TypeWithInfo<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.display(&self.1, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MersType: Any + Debug + Send + Sync {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result;
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
None
|
None
|
||||||
@ -93,13 +157,20 @@ pub trait MersType: Any + Debug + Display + Send + Sync {
|
|||||||
}
|
}
|
||||||
fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
|
fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
|
||||||
self.simplify_for_display(info)
|
self.simplify_for_display(info)
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.with_info(info).to_string())
|
||||||
.unwrap_or_else(|| self.to_string())
|
.unwrap_or_else(|| self.with_info(info).to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct TypeWithOnlyName(pub(crate) String);
|
pub(crate) struct TypeWithOnlyName(pub(crate) String);
|
||||||
impl MersType for TypeWithOnlyName {
|
impl MersType for TypeWithOnlyName {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -447,20 +518,20 @@ impl Type {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
pub fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
|
pub fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
|
||||||
self.simplify_for_display(info).to_string()
|
self.simplify_for_display(info).with_info(info).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for Type {
|
impl Type {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn display(&self, info: &DisplayInfo, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if self.types.is_empty() {
|
if self.types.is_empty() {
|
||||||
write!(f, "<unreachable>")
|
write!(f, "<unreachable>")
|
||||||
} else {
|
} else {
|
||||||
// if self.types.len() > 1 {
|
// if self.types.len() > 1 {
|
||||||
// write!(f, "{{")?;
|
// write!(f, "{{")?;
|
||||||
// }
|
// }
|
||||||
write!(f, "{}", self.types[0])?;
|
write!(f, "{}", self.types[0].with_display(info))?;
|
||||||
for t in self.types.iter().skip(1) {
|
for t in self.types.iter().skip(1) {
|
||||||
write!(f, "/{t}")?;
|
write!(f, "/{}", t.with_display(info))?;
|
||||||
}
|
}
|
||||||
// if self.types.len() > 1 {
|
// if self.types.len() > 1 {
|
||||||
// write!(f, "}}")?;
|
// write!(f, "}}")?;
|
||||||
|
@ -1,13 +1,61 @@
|
|||||||
use std::{fmt::Display, sync::Arc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Data, MersData, MersType, Type};
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
|
use super::{Data, MersData, MersDataWInfo, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Object(pub Vec<(String, Data)>);
|
pub struct Object(Vec<(usize, Data)>);
|
||||||
|
impl Object {
|
||||||
|
pub fn new(v: Vec<(usize, Data)>) -> Self {
|
||||||
|
Self(v)
|
||||||
|
}
|
||||||
|
pub fn get(&self, f: usize) -> Option<&Data> {
|
||||||
|
self.iter().find(|v| v.0 == f).map(|v| &v.1)
|
||||||
|
}
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<(usize, Data)> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ObjectT(pub Vec<(String, Type)>);
|
pub struct ObjectT(Vec<(usize, Type)>);
|
||||||
|
impl ObjectT {
|
||||||
|
pub fn new(v: Vec<(usize, Type)>) -> Self {
|
||||||
|
Self(v)
|
||||||
|
}
|
||||||
|
pub fn get(&self, f: usize) -> Option<&Type> {
|
||||||
|
self.iter().find(|v| v.0 == f).map(|v| &v.1)
|
||||||
|
}
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<(usize, Type)> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MersData for Object {
|
impl MersData for Object {
|
||||||
|
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let mut comma_sep = false;
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for (field, val) in self.iter() {
|
||||||
|
if comma_sep {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}: {}",
|
||||||
|
info.get_object_field_name(*field),
|
||||||
|
val.get().with_display(info)
|
||||||
|
)?;
|
||||||
|
comma_sep = true;
|
||||||
|
}
|
||||||
|
write!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
self == other
|
self == other
|
||||||
@ -20,8 +68,7 @@ impl MersData for Object {
|
|||||||
}
|
}
|
||||||
fn as_type(&self) -> Type {
|
fn as_type(&self) -> Type {
|
||||||
Type::new(ObjectT(
|
Type::new(ObjectT(
|
||||||
self.0
|
self.iter()
|
||||||
.iter()
|
|
||||||
.map(|(n, v)| (n.clone(), v.get().as_type()))
|
.map(|(n, v)| (n.clone(), v.get().as_type()))
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
@ -38,14 +85,35 @@ impl MersData for Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MersType for ObjectT {
|
impl MersType for ObjectT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
let mut comma_sep = false;
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for (field, t) in self.iter() {
|
||||||
|
if comma_sep {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}: {}",
|
||||||
|
info.get_object_field_name(*field),
|
||||||
|
t.with_display(info)
|
||||||
|
)?;
|
||||||
|
comma_sep = true;
|
||||||
|
}
|
||||||
|
write!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some_and(|other| {
|
other.as_any().downcast_ref::<Self>().is_some_and(|other| {
|
||||||
self.0.len() == other.0.len()
|
self.len() == other.len()
|
||||||
&& self
|
&& other.iter().all(|(field, target_type)| {
|
||||||
.0
|
self.get(*field)
|
||||||
.iter()
|
.is_some_and(|self_type| self_type.is_same_type_as(target_type))
|
||||||
.zip(other.0.iter())
|
})
|
||||||
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_same_type_as(t2))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn is_included_in(&self, target: &dyn MersType) -> bool {
|
fn is_included_in(&self, target: &dyn MersType) -> bool {
|
||||||
@ -53,16 +121,15 @@ impl MersType for ObjectT {
|
|||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<Self>()
|
.downcast_ref::<Self>()
|
||||||
.is_some_and(|target| {
|
.is_some_and(|target| {
|
||||||
self.0.len() >= target.0.len()
|
self.len() >= target.len()
|
||||||
&& self
|
&& target.iter().all(|(field, target_type)| {
|
||||||
.0
|
self.get(*field)
|
||||||
.iter()
|
.is_some_and(|self_type| self_type.is_included_in(target_type))
|
||||||
.zip(target.0.iter())
|
})
|
||||||
.all(|((s1, t1), (s2, t2))| s1 == s2 && t1.is_included_in(t2))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn subtypes(&self, acc: &mut Type) {
|
fn subtypes(&self, acc: &mut Type) {
|
||||||
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.0.len()));
|
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.len()));
|
||||||
}
|
}
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
@ -83,44 +150,13 @@ impl MersType for ObjectT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Object {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let mut comma_sep = false;
|
|
||||||
write!(f, "{{")?;
|
|
||||||
for (name, val) in self.0.iter() {
|
|
||||||
if comma_sep {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{name}: {}", val.get())?;
|
|
||||||
comma_sep = true;
|
|
||||||
}
|
|
||||||
write!(f, "}}")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for ObjectT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let mut comma_sep = false;
|
|
||||||
write!(f, "{{")?;
|
|
||||||
for (name, t) in self.0.iter() {
|
|
||||||
if comma_sep {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{name}: {t}")?;
|
|
||||||
comma_sep = true;
|
|
||||||
}
|
|
||||||
write!(f, "}}")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectT {
|
impl ObjectT {
|
||||||
pub fn gen_subtypes_recursively(
|
pub fn gen_subtypes_recursively(
|
||||||
&self,
|
&self,
|
||||||
acc: &mut Type,
|
acc: &mut Type,
|
||||||
types: &mut Vec<(String, Arc<dyn MersType>)>,
|
types: &mut Vec<(usize, Arc<dyn MersType>)>,
|
||||||
) {
|
) {
|
||||||
if types.len() >= self.0.len() {
|
if types.len() >= self.len() {
|
||||||
let nt = Self(
|
let nt = Self(
|
||||||
types
|
types
|
||||||
.iter()
|
.iter()
|
||||||
@ -137,3 +173,18 @@ impl ObjectT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) trait ObjectFieldsMap {
|
||||||
|
fn get_or_add_field(&self, field: &str) -> usize;
|
||||||
|
}
|
||||||
|
impl ObjectFieldsMap for Arc<Mutex<HashMap<String, usize>>> {
|
||||||
|
fn get_or_add_field(&self, field: &str) -> usize {
|
||||||
|
let mut s = self.lock().unwrap();
|
||||||
|
if let Some(f) = s.get(field) {
|
||||||
|
return *f;
|
||||||
|
}
|
||||||
|
let o = s.len();
|
||||||
|
s.insert(field.to_owned(), o);
|
||||||
|
o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
fmt::Display,
|
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::errors::CheckError;
|
use crate::{errors::CheckError, info::DisplayInfo};
|
||||||
|
|
||||||
use super::{Data, MersData, MersType, Type};
|
use super::{Data, MersData, MersType, Type};
|
||||||
|
|
||||||
@ -12,6 +11,9 @@ use super::{Data, MersData, MersType, Type};
|
|||||||
pub struct Reference(pub Arc<RwLock<Data>>);
|
pub struct Reference(pub Arc<RwLock<Data>>);
|
||||||
|
|
||||||
impl MersData for Reference {
|
impl MersData for Reference {
|
||||||
|
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
self.0.read().unwrap().get().display(info, f)
|
||||||
|
}
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
let inner = self.0.read().unwrap();
|
let inner = self.0.read().unwrap();
|
||||||
let inner = inner.get();
|
let inner = inner.get();
|
||||||
@ -88,6 +90,17 @@ impl MersData for Reference {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReferenceT(pub Type);
|
pub struct ReferenceT(pub Type);
|
||||||
impl MersType for ReferenceT {
|
impl MersType for ReferenceT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
if self.0.types.len() > 1 {
|
||||||
|
write!(f, "&{{{}}}", self.0.with_display(info))
|
||||||
|
} else {
|
||||||
|
write!(f, "&{}", self.0.with_display(info))
|
||||||
|
}
|
||||||
|
}
|
||||||
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
fn executable(&self) -> Option<crate::data::function::FunctionT> {
|
||||||
let mut funcs: Vec<crate::data::function::FunctionT> = vec![];
|
let mut funcs: Vec<crate::data::function::FunctionT> = vec![];
|
||||||
for func in self.0.types.iter() {
|
for func in self.0.types.iter() {
|
||||||
@ -96,13 +109,16 @@ impl MersType for ReferenceT {
|
|||||||
.downcast_ref::<crate::data::function::FunctionT>()?,
|
.downcast_ref::<crate::data::function::FunctionT>()?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Some(super::function::FunctionT(Ok(Arc::new(move |a| {
|
Some(super::function::FunctionT(
|
||||||
|
Ok(Arc::new(move |a, _| {
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
for func in funcs.iter() {
|
for func in funcs.iter() {
|
||||||
out.add_all(&func.o(a)?);
|
out.add_all(&func.o(a)?);
|
||||||
}
|
}
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}))))
|
})),
|
||||||
|
crate::info::Info::neverused(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
fn iterable(&self) -> Option<Type> {
|
fn iterable(&self) -> Option<Type> {
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
@ -156,18 +172,3 @@ impl MersType for ReferenceT {
|
|||||||
Some(&self.0)
|
Some(&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Reference {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "&{}", self.0.read().unwrap().get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for ReferenceT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
if self.0.types.len() > 1 {
|
|
||||||
write!(f, "&{{{}}}", self.0)
|
|
||||||
} else {
|
|
||||||
write!(f, "&{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
|
use crate::info::DisplayInfo;
|
||||||
|
|
||||||
use super::{MersData, MersType, Type};
|
use super::{MersData, MersType, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct String(pub std::string::String);
|
pub struct String(pub std::string::String);
|
||||||
|
|
||||||
impl MersData for String {
|
impl MersData for String {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -33,6 +38,13 @@ impl MersData for String {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StringT;
|
pub struct StringT;
|
||||||
impl MersType for StringT {
|
impl MersType for StringT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
other.as_any().downcast_ref::<Self>().is_some()
|
other.as_any().downcast_ref::<Self>().is_some()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{any::Any, fmt::Display, sync::Arc};
|
use std::{any::Any, sync::Arc};
|
||||||
|
|
||||||
use crate::errors::CheckError;
|
use crate::{errors::CheckError, info::DisplayInfo};
|
||||||
|
|
||||||
use super::{Data, MersData, MersType, Type};
|
use super::{Data, MersData, MersType, Type};
|
||||||
|
|
||||||
@ -17,6 +17,17 @@ impl Tuple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MersData for Tuple {
|
impl MersData for Tuple {
|
||||||
|
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "(")?;
|
||||||
|
for (i, c) in self.0.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
c.get().display(info, f)?;
|
||||||
|
}
|
||||||
|
write!(f, ")")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0 == self.0
|
other.0 == self.0
|
||||||
@ -47,6 +58,21 @@ impl MersData for Tuple {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TupleT(pub Vec<Type>);
|
pub struct TupleT(pub Vec<Type>);
|
||||||
impl MersType for TupleT {
|
impl MersType for TupleT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "(")?;
|
||||||
|
for (i, c) in self.0.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{}", c.with_display(info))?;
|
||||||
|
}
|
||||||
|
write!(f, ")")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn iterable(&self) -> Option<Type> {
|
fn iterable(&self) -> Option<Type> {
|
||||||
let mut o = Type::empty();
|
let mut o = Type::empty();
|
||||||
for t in self.0.iter() {
|
for t in self.0.iter() {
|
||||||
@ -100,33 +126,6 @@ impl MersType for TupleT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Tuple {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "(")?;
|
|
||||||
for (i, c) in self.0.iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{}", c.get())?;
|
|
||||||
}
|
|
||||||
write!(f, ")")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for TupleT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "(")?;
|
|
||||||
for (i, c) in self.0.iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{}", c)?;
|
|
||||||
}
|
|
||||||
write!(f, ")")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TupleT {
|
impl TupleT {
|
||||||
pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) {
|
pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) {
|
||||||
if types.len() >= self.0.len() {
|
if types.len() >= self.0.len() {
|
||||||
|
@ -83,6 +83,7 @@ pub enum EColor {
|
|||||||
BadCharInFunctionType,
|
BadCharInFunctionType,
|
||||||
BadCharAtStartOfStatement,
|
BadCharAtStartOfStatement,
|
||||||
BadTypeFromParsed,
|
BadTypeFromParsed,
|
||||||
|
ObjectDuplicateField,
|
||||||
TypeAnnotationNoClosingBracket,
|
TypeAnnotationNoClosingBracket,
|
||||||
TryBadSyntax,
|
TryBadSyntax,
|
||||||
TryNoFunctionFound,
|
TryNoFunctionFound,
|
||||||
|
@ -78,7 +78,7 @@ pub fn default_theme<C>(
|
|||||||
TryBadSyntax => hard_err,
|
TryBadSyntax => hard_err,
|
||||||
TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing,
|
TypeAnnotationNoClosingBracket | BracketedRefTypeNoClosingBracket => missing,
|
||||||
|
|
||||||
BadTypeFromParsed => type_wrong_b,
|
BadTypeFromParsed | ObjectDuplicateField => type_wrong_b,
|
||||||
|
|
||||||
// -- type-errors --
|
// -- type-errors --
|
||||||
IfConditionNotBool => type_wrong,
|
IfConditionNotBool => type_wrong,
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use std::fmt::Debug;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Info<L: Local> {
|
pub struct Info<L: Local> {
|
||||||
@ -7,24 +11,68 @@ pub struct Info<L: Local> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Local> Info<L> {
|
impl<L: Local> Info<L> {
|
||||||
|
pub fn new(global: L::Global) -> Self {
|
||||||
|
Self {
|
||||||
|
scopes: vec![L::default()],
|
||||||
|
global,
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Returns self, but completely empty (even without globals).
|
/// Returns self, but completely empty (even without globals).
|
||||||
/// Only use this if you assume this Info will never be used.
|
/// Only use this if you assume this Info will never be used.
|
||||||
pub fn neverused() -> Self {
|
pub fn neverused() -> Self {
|
||||||
Self {
|
Self::new(L::neverused_global())
|
||||||
scopes: vec![],
|
|
||||||
global: L::Global::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Local: Default + Debug {
|
pub trait Local: Default + Debug {
|
||||||
type VariableIdentifier;
|
type VariableIdentifier;
|
||||||
type VariableData;
|
type VariableData;
|
||||||
type Global: Default + Debug + Clone;
|
type Global: Debug + Clone;
|
||||||
|
fn neverused_global() -> Self::Global;
|
||||||
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
|
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
|
||||||
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
|
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
|
||||||
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
|
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
|
||||||
fn duplicate(&self) -> Self;
|
fn duplicate(&self) -> Self;
|
||||||
|
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a>;
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct DisplayInfo<'a> {
|
||||||
|
pub object_fields: &'a Arc<Mutex<HashMap<String, usize>>>,
|
||||||
|
pub object_fields_rev: &'a Arc<Mutex<Vec<String>>>,
|
||||||
|
}
|
||||||
|
pub struct GetObjectFieldNameDisplay<'a>(&'a DisplayInfo<'a>, usize);
|
||||||
|
impl<'a> Display for GetObjectFieldNameDisplay<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut object_fields_rev = self.0.object_fields_rev.lock().unwrap();
|
||||||
|
if self.1 < object_fields_rev.len() {
|
||||||
|
write!(f, "{}", object_fields_rev[self.1])
|
||||||
|
} else {
|
||||||
|
let object_fields = self.0.object_fields.lock().unwrap();
|
||||||
|
if self.1 < object_fields.len() {
|
||||||
|
let mut ofr = object_fields
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.0.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
ofr.sort_by_cached_key(|v| object_fields.get(v).unwrap());
|
||||||
|
*object_fields_rev = ofr;
|
||||||
|
}
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
object_fields_rev
|
||||||
|
.get(self.1)
|
||||||
|
.map(String::as_str)
|
||||||
|
.unwrap_or("<UNKNOWN-OBJECT-FIELD>")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DisplayInfo<'_> {
|
||||||
|
/// this is almost always a constant-time operation, indexing a `Vec` with `field: usize`.
|
||||||
|
/// And even if it isn't, the second, third, ... time will be, so there is no need to cache the returned value.
|
||||||
|
pub fn get_object_field_name<'a>(&'a self, field: usize) -> GetObjectFieldNameDisplay<'a> {
|
||||||
|
GetObjectFieldNameDisplay(self, field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Local> Info<L> {
|
impl<L: Local> Info<L> {
|
||||||
@ -35,34 +83,26 @@ impl<L: Local> Info<L> {
|
|||||||
pub fn end_scope(&mut self) {
|
pub fn end_scope(&mut self) {
|
||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn display_info<'a>(&'a self) -> DisplayInfo<'a> {
|
||||||
|
L::display_info(&self.global)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Local> Local for Info<L> {
|
impl<L: Local> Info<L> {
|
||||||
type VariableIdentifier = L::VariableIdentifier;
|
pub fn init_var(&mut self, id: L::VariableIdentifier, value: L::VariableData) {
|
||||||
type VariableData = L::VariableData;
|
|
||||||
type Global = ();
|
|
||||||
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
|
||||||
self.scopes.last_mut().unwrap().init_var(id, value)
|
self.scopes.last_mut().unwrap().init_var(id, value)
|
||||||
}
|
}
|
||||||
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData> {
|
pub fn get_var(&self, id: &L::VariableIdentifier) -> Option<&L::VariableData> {
|
||||||
self.scopes.iter().rev().find_map(|l| l.get_var(id))
|
self.scopes.iter().rev().find_map(|l| l.get_var(id))
|
||||||
}
|
}
|
||||||
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData> {
|
pub fn get_var_mut(&mut self, id: &L::VariableIdentifier) -> Option<&mut L::VariableData> {
|
||||||
self.scopes.iter_mut().rev().find_map(|l| l.get_var_mut(id))
|
self.scopes.iter_mut().rev().find_map(|l| l.get_var_mut(id))
|
||||||
}
|
}
|
||||||
fn duplicate(&self) -> Self {
|
pub fn duplicate(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
|
scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
|
||||||
global: self.global.clone(),
|
global: self.global.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Local> Default for Info<L> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
scopes: vec![L::default()],
|
|
||||||
global: L::Global::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -358,11 +358,24 @@ pub fn parse_no_chain(
|
|||||||
src.next_char();
|
src.next_char();
|
||||||
let pos_in_src_after_bracket = src.get_pos();
|
let pos_in_src_after_bracket = src.get_pos();
|
||||||
{
|
{
|
||||||
let mut elems = vec![];
|
let mut elems: Vec<(String, _)> = vec![];
|
||||||
loop {
|
loop {
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
if src.peek_char() == Some('}') {
|
if src.peek_char() == Some('}') {
|
||||||
src.next_char();
|
src.next_char();
|
||||||
|
for (i, a) in elems.iter().enumerate() {
|
||||||
|
if elems.iter().skip(1 + i).any(|b| a.0 == b.0) {
|
||||||
|
return Err(CheckError::new()
|
||||||
|
.src(vec![(
|
||||||
|
(pos_in_src, src.get_pos(), srca).into(),
|
||||||
|
Some(EColor::ObjectDuplicateField),
|
||||||
|
)])
|
||||||
|
.msg_str(format!(
|
||||||
|
"This object contains more than one field named `{}`",
|
||||||
|
a.0
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
return Ok(Some(Box::new(program::parsed::object::Object {
|
return Ok(Some(Box::new(program::parsed::object::Object {
|
||||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||||
elems,
|
elems,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Type},
|
data::{self, object::ObjectFieldsMap, Type},
|
||||||
errors::{CheckError, EColor},
|
errors::{CheckError, EColor},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,6 +173,19 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i, a) in inner.iter().enumerate() {
|
||||||
|
if inner.iter().skip(1 + i).any(|b| a.0 == b.0) {
|
||||||
|
return Err(CheckError::new()
|
||||||
|
.src(vec![(
|
||||||
|
(pos_in_src, src.get_pos(), srca).into(),
|
||||||
|
Some(EColor::ObjectDuplicateField),
|
||||||
|
)])
|
||||||
|
.msg_str(format!(
|
||||||
|
"This object type contains more than one field named `{}`",
|
||||||
|
a.0
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
ParsedType::Object(inner)
|
ParsedType::Object(inner)
|
||||||
}
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
@ -239,20 +252,24 @@ pub fn type_from_parsed(
|
|||||||
.map(|v| type_from_parsed(v, info))
|
.map(|v| type_from_parsed(v, info))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
))),
|
))),
|
||||||
ParsedType::Object(o) => as_type.add(Arc::new(data::object::ObjectT(
|
ParsedType::Object(o) => as_type.add(Arc::new(data::object::ObjectT::new(
|
||||||
o.iter()
|
o.iter()
|
||||||
.map(|(s, v)| -> Result<_, CheckError> {
|
.map(|(s, v)| -> Result<_, CheckError> {
|
||||||
Ok((s.clone(), type_from_parsed(v, info)?))
|
Ok((
|
||||||
|
info.global.object_fields.get_or_add_field(&s),
|
||||||
|
type_from_parsed(v, info)?,
|
||||||
|
))
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
))),
|
))),
|
||||||
ParsedType::Function(v) => {
|
ParsedType::Function(v) => as_type.add(Arc::new(data::function::FunctionT(
|
||||||
as_type.add(Arc::new(data::function::FunctionT(Err(Arc::new(
|
Err(Arc::new(
|
||||||
v.iter()
|
v.iter()
|
||||||
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
|
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
|
||||||
.collect::<Result<_, CheckError>>()?,
|
.collect::<Result<_, CheckError>>()?,
|
||||||
)))))
|
)),
|
||||||
}
|
info.clone(),
|
||||||
|
))),
|
||||||
ParsedType::Type(name) => match info
|
ParsedType::Type(name) => match info
|
||||||
.scopes
|
.scopes
|
||||||
.iter()
|
.iter()
|
||||||
@ -274,7 +291,8 @@ pub fn type_from_parsed(
|
|||||||
{
|
{
|
||||||
Some(Ok(t)) => {
|
Some(Ok(t)) => {
|
||||||
return Err(CheckError::new().msg_str(format!(
|
return Err(CheckError::new().msg_str(format!(
|
||||||
"Type: specified type with info, but type {t} doesn't need it"
|
"Type: specified type with info, but type {} doesn't need it",
|
||||||
|
t.with_info(info)
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
Some(Err(f)) => as_type.add_all(&*f(&additional_info, info)?),
|
Some(Err(f)) => as_type.add_all(&*f(&additional_info, info)?),
|
||||||
|
@ -58,8 +58,12 @@ pub trait StaticMersFunc: Sized + 'static + Send + Sync {
|
|||||||
Some(Err(e)) => Err(e),
|
Some(Err(e)) => Err(e),
|
||||||
None => Err(CheckError::from(format!(
|
None => Err(CheckError::from(format!(
|
||||||
"unexpected argument of type {}, expected {}",
|
"unexpected argument of type {}, expected {}",
|
||||||
a.get().as_type(),
|
a.get().as_type().with_info(i),
|
||||||
Type::new(data::function::FunctionT(Err(Arc::new(Self::types()))))
|
Type::new(data::function::FunctionT(
|
||||||
|
Err(Arc::new(Self::types())),
|
||||||
|
crate::info::Info::neverused()
|
||||||
|
))
|
||||||
|
.with_info(i)
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
data::{self, Data, MersData, Type},
|
data::{self, Data, MersData, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
info::Local,
|
info::Local,
|
||||||
program::run::CheckInfo,
|
program::run::{CheckInfo, CheckLocalGlobalInfo, RunLocalGlobalInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod gen;
|
pub mod gen;
|
||||||
@ -63,7 +63,15 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut info_check: CheckInfo = Default::default();
|
let info_parsed = crate::program::parsed::Info::new(
|
||||||
|
crate::program::parsed::LocalGlobalInfo::new(Arc::new(Default::default())),
|
||||||
|
);
|
||||||
|
let mut info_check = CheckInfo::new(CheckLocalGlobalInfo::new(Arc::clone(
|
||||||
|
&info_parsed.global.object_fields,
|
||||||
|
)));
|
||||||
|
let info_run = crate::program::run::Info::new(RunLocalGlobalInfo::new(Arc::clone(
|
||||||
|
&info_parsed.global.object_fields,
|
||||||
|
)));
|
||||||
macro_rules! init_d {
|
macro_rules! init_d {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
let t = $e;
|
let t = $e;
|
||||||
@ -89,8 +97,8 @@ impl Config {
|
|||||||
init_d!(data::string::StringT);
|
init_d!(data::string::StringT);
|
||||||
Self {
|
Self {
|
||||||
globals: 0,
|
globals: 0,
|
||||||
info_parsed: Default::default(),
|
info_parsed,
|
||||||
info_run: Default::default(),
|
info_run,
|
||||||
info_check,
|
info_check,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,29 +7,46 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn to_mers_func(
|
pub fn to_mers_func(
|
||||||
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
|
out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result<Type, CheckError>
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: Info::neverused(),
|
info: Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(Info::neverused())),
|
info_check: Arc::new(Mutex::new(Info::neverused())),
|
||||||
out: Ok(Arc::new(move |a, _| out(a))),
|
out: Ok(Arc::new(move |a, i| out(a, i))),
|
||||||
run: Arc::new(move |a, _| run(a)),
|
run: Arc::new(move |a, i| run(a, i)),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_mers_func_with_in_type(
|
pub fn to_mers_func_with_in_type(
|
||||||
in_type: Type,
|
in_type: Type,
|
||||||
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
|
out: impl Fn(&Type, &mut crate::program::run::CheckInfo) -> Result<Type, CheckError>
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
to_mers_func(
|
to_mers_func(
|
||||||
move |a| {
|
move |a, i| {
|
||||||
if a.is_included_in(&in_type) {
|
if a.is_included_in(&in_type) {
|
||||||
out(a)
|
out(a, i)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Function argument must be {in_type}, but was {a}.").into())
|
Err(format!(
|
||||||
|
"Function argument must be {}, but was {}.",
|
||||||
|
in_type.with_info(i),
|
||||||
|
a.with_info(i)
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
run,
|
run,
|
||||||
@ -39,16 +56,19 @@ pub fn to_mers_func_with_in_type(
|
|||||||
pub fn to_mers_func_with_in_out_types(
|
pub fn to_mers_func_with_in_out_types(
|
||||||
in_type: Type,
|
in_type: Type,
|
||||||
out_type: Type,
|
out_type: Type,
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
run: impl Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
data::function::Function::new_static(vec![(in_type, out_type)], move |a, _| run(a))
|
data::function::Function::new_static(vec![(in_type, out_type)], move |a, i| run(a, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_mers_func_concrete_string_to_any(
|
pub fn to_mers_func_concrete_string_to_any(
|
||||||
out_type: Type,
|
out_type: Type,
|
||||||
f: impl Fn(&str) -> Result<Data, CheckError> + Send + Sync + 'static,
|
f: impl Fn(&str) -> Result<Data, CheckError> + Send + Sync + 'static,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
to_mers_func_with_in_out_types(Type::new(data::string::StringT), out_type, move |a| {
|
to_mers_func_with_in_out_types(Type::new(data::string::StringT), out_type, move |a, _| {
|
||||||
f(a.get()
|
f(a.get()
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<data::string::String>()
|
.downcast_ref::<data::string::String>()
|
||||||
@ -75,7 +95,7 @@ pub fn to_mers_func_concrete_string_string_to_any(
|
|||||||
Type::new(data::string::StringT),
|
Type::new(data::string::StringT),
|
||||||
])),
|
])),
|
||||||
out_type,
|
out_type,
|
||||||
move |a| {
|
move |a, _| {
|
||||||
let a = a.get();
|
let a = a.get();
|
||||||
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
|
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
|
||||||
let l = a[0].get();
|
let l = a[0].get();
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, bool::bool_type, Data, Type},
|
data::{self, bool::bool_type, Data, MersTypeWInfo, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
program::run::{CheckInfo, Info},
|
program::run::{CheckInfo, Info},
|
||||||
};
|
};
|
||||||
@ -30,7 +30,7 @@ impl Config {
|
|||||||
.add_var("lock_update", data::function::Function {
|
.add_var("lock_update", data::function::Function {
|
||||||
info: Info::neverused(),
|
info: Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
if t.0.len() == 2 {
|
if t.0.len() == 2 {
|
||||||
@ -42,23 +42,23 @@ impl Config {
|
|||||||
match f.o(&arg) {
|
match f.o(&arg) {
|
||||||
Ok(out) => {
|
Ok(out) => {
|
||||||
if !out.is_included_in(&arg) {
|
if !out.is_included_in(&arg) {
|
||||||
return Err(format!("Function returns a value of type {out}, which isn't included in the type of the reference, {arg}.").into());
|
return Err(format!("Function returns a value of type {}, which isn't included in the type of the reference, {}.", out.with_info(i), arg.with_info(i)).into());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => return Err(CheckError::new().msg_str(format!("Invalid argument type {arg} for function")).err(e)),
|
Err(e) => return Err(CheckError::new().msg_str(format!("Invalid argument type {} for function", arg.with_info(i))).err(e)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Arguments must be (reference, function)").into());
|
return Err(format!("Arguments must be (reference, function)").into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Arguments must be (reference, function), but {arg_ref} isn't a reference").into());
|
return Err(format!("Arguments must be (reference, function), but {} isn't a reference", arg_ref.with_info(i)).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Can't call lock_update on tuple type {t} with length != 2, which is part of the argument type {a}.").into());
|
return Err(format!("Can't call lock_update on tuple type {} with length != 2, which is part of the argument type {}.", t.with_info(i), a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Can't call lock_update on non-tuple type {t}, which is part of the argument type {a}.").into());
|
return Err(format!("Can't call lock_update on non-tuple type {}, which is part of the argument type {}.", t.with_info(i), a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Type::empty_tuple())
|
Ok(Type::empty_tuple())
|
||||||
@ -98,10 +98,10 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: Info::neverused(),
|
info: Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
for t in &a.types {
|
for t in &a.types {
|
||||||
if t.as_any().downcast_ref::<data::string::StringT>().is_none() && t.as_any().downcast_ref::<data::tuple::TupleT>().is_none() && t.iterable().is_none() {
|
if t.as_any().downcast_ref::<data::string::StringT>().is_none() && t.as_any().downcast_ref::<data::tuple::TupleT>().is_none() && t.iterable().is_none() {
|
||||||
return Err(format!("cannot get length of {t} (must be a tuple, string or iterable)").into());
|
return Err(format!("cannot get length of {} (must be a tuple, string or iterable)", t.with_info(i)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Type::new(data::int::IntT))
|
Ok(Type::new(data::int::IntT))
|
||||||
@ -174,7 +174,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: Info::neverused(),
|
info: Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into())
|
out: Ok(Arc::new(|a, i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {}", a.with_info(i)).into())
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
if let Some(r) = a
|
if let Some(r) = a
|
||||||
|
@ -6,8 +6,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, MersType, Type},
|
data::{self, object::ObjectFieldsMap, Data, MersData, MersDataWInfo, MersType, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
|
info::DisplayInfo,
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
|
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![
|
Arc::new(data::tuple::TupleT(vec![
|
||||||
@ -37,13 +38,13 @@ impl Config {
|
|||||||
Type::new(data::string::StringT),
|
Type::new(data::string::StringT),
|
||||||
Type::new(data::string::StringT),
|
Type::new(data::string::StringT),
|
||||||
])),
|
])),
|
||||||
Arc::new(data::object::ObjectT(vec![("run_command_error".to_owned(), Type::new(data::string::StringT))]))
|
Arc::new(data::object::ObjectT::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Type::new(data::string::StringT))]))
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("run_command called with invalid arguments (must be (String, Iter<String>))").into());
|
return Err(format!("run_command called with invalid arguments (must be (String, Iter<String>))").into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
let a = a.get();
|
let a = a.get();
|
||||||
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
||||||
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
|
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
|
||||||
@ -52,7 +53,7 @@ impl Config {
|
|||||||
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
|
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
|
||||||
args.get().iterable().unwrap(),
|
args.get().iterable().unwrap(),
|
||||||
);
|
);
|
||||||
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
|
let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::<Result<Vec<_>, _>>()?;
|
||||||
match Command::new(&cmd.0)
|
match Command::new(&cmd.0)
|
||||||
.args(args)
|
.args(args)
|
||||||
.output()
|
.output()
|
||||||
@ -73,7 +74,7 @@ impl Config {
|
|||||||
Data::new(data::string::String(stderr)),
|
Data::new(data::string::String(stderr)),
|
||||||
])))
|
])))
|
||||||
}
|
}
|
||||||
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
|
Err(e) => Ok(Data::new(data::object::Object::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Data::new(data::string::String(e.to_string())))]))),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
@ -84,17 +85,17 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
|
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(ChildProcessT),
|
Arc::new(ChildProcessT),
|
||||||
Arc::new(data::object::ObjectT(vec![("run_command_error".to_owned(), Type::new(data::string::StringT))]))
|
Arc::new(data::object::ObjectT::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Type::new(data::string::StringT))]))
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("spawn_command called with invalid arguments (must be (String, Iter<String>))").into());
|
return Err(format!("spawn_command called with invalid arguments (must be (String, Iter<String>))").into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
let a = a.get();
|
let a = a.get();
|
||||||
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
||||||
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
|
let (cmd, args) = (&cmd.0[0], &cmd.0[1]);
|
||||||
@ -103,7 +104,7 @@ impl Config {
|
|||||||
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
|
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
|
||||||
args.get().iterable().unwrap(),
|
args.get().iterable().unwrap(),
|
||||||
);
|
);
|
||||||
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
|
let args = args.map(|v| v.map(|v| v.get().with_info(i).to_string())).collect::<Result<Vec<_>, _>>()?;
|
||||||
match Command::new(&cmd.0)
|
match Command::new(&cmd.0)
|
||||||
.args(args)
|
.args(args)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
@ -117,7 +118,7 @@ impl Config {
|
|||||||
let c = BufReader::new(child.stderr.take().unwrap());
|
let c = BufReader::new(child.stderr.take().unwrap());
|
||||||
Ok(Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c))))))
|
Ok(Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c))))))
|
||||||
}
|
}
|
||||||
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
|
Err(e) => Ok(Data::new(data::object::Object::new(vec![(i.global.object_fields.get_or_add_field("run_command_error"), Data::new(data::string::String(e.to_string())))]))),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
@ -128,14 +129,14 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![data::bool::bool_type()])),
|
Arc::new(data::tuple::TupleT(vec![data::bool::bool_type()])),
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_exited called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_exited called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -156,7 +157,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::int::IntT),
|
Arc::new(data::int::IntT),
|
||||||
@ -165,7 +166,7 @@ impl Config {
|
|||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_await called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_await called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -190,11 +191,11 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.types.iter().all(|a| a.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) {
|
if a.types.iter().all(|a| a.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) {
|
||||||
Ok(data::bool::bool_type())
|
Ok(data::bool::bool_type())
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter<Byte>)` type {a}").into());
|
return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter<Byte>)` type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -219,11 +220,11 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) {
|
if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) {
|
||||||
Ok(data::bool::bool_type())
|
Ok(data::bool::bool_type())
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_write_string called on non-`(ChildProcess, String)` type {a}").into());
|
return Err(format!("childproc_write_string called on non-`(ChildProcess, String)` type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -248,14 +249,14 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
|
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_read_byte called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_read_byte called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -277,14 +278,14 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
|
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_readerr_byte called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_readerr_byte called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -306,14 +307,14 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
|
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_read_line called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -335,14 +336,14 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if a.is_included_in_single(&ChildProcessT) {
|
if a.is_included_in_single(&ChildProcessT) {
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
|
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
Arc::new(data::tuple::TupleT(vec![])),
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
|
return Err(format!("childproc_read_line called on non-ChildProcess type {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -376,6 +377,9 @@ pub struct ChildProcess(
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ChildProcessT;
|
pub struct ChildProcessT;
|
||||||
impl MersData for ChildProcess {
|
impl MersData for ChildProcess {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
|
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -410,6 +414,13 @@ impl Display for ChildProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for ChildProcessT {
|
impl MersType for ChildProcessT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
_info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn iterable(&self) -> Option<Type> {
|
fn iterable(&self) -> Option<Type> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, MersTypeWInfo, Type},
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
for a in a.types.iter() {
|
for a in a.types.iter() {
|
||||||
if let Some(t) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(t) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
@ -25,7 +25,7 @@ impl Config {
|
|||||||
if !t.0[1].is_included_in_single(&data::int::IntT) {
|
if !t.0[1].is_included_in_single(&data::int::IntT) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"called get with non-int index of type {}",
|
"called get with non-int index of type {}",
|
||||||
t.0[1]
|
t.0[1].with_info(i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -33,12 +33,16 @@ impl Config {
|
|||||||
out.add_all(&v);
|
out.add_all(&v);
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"called get on non-gettable type {t}, part of {a}"
|
"called get on non-gettable type {}, part of {}",
|
||||||
|
t.with_info(i),
|
||||||
|
a.with_info(i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("called get on non-tuple type {a}").into());
|
return Err(
|
||||||
|
format!("called get on non-tuple type {}", a.with_info(i)).into()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Type::newm(vec![
|
Ok(Type::newm(vec![
|
||||||
|
@ -7,9 +7,10 @@ use crate::{
|
|||||||
data::{
|
data::{
|
||||||
self,
|
self,
|
||||||
function::{Function, FunctionT},
|
function::{Function, FunctionT},
|
||||||
Data, MersData, MersType, Type,
|
Data, MersData, MersType, MersTypeWInfo, Type,
|
||||||
},
|
},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
|
info::DisplayInfo,
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
for a in &a.types {
|
for a in &a.types {
|
||||||
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
|
if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
|
||||||
@ -70,7 +71,8 @@ impl Config {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"for_each called on tuple not containing iterable and function: {v} is {}",
|
"for_each called on tuple not containing iterable and function: {} is {}",
|
||||||
|
v.with_info(i),
|
||||||
if v.iterable().is_some() { "iterable" } else { "not iterable" },
|
if v.iterable().is_some() { "iterable" } else { "not iterable" },
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
@ -133,13 +135,13 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
let data = if let Some(a) = a.iterable() {
|
let data = if let Some(a) = a.iterable() {
|
||||||
a
|
a
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("cannot call enumerate on non-iterable type {a}.").into());
|
return Err(format!("cannot call enumerate on non-iterable type {}.", a.with_info(i)).into());
|
||||||
};
|
};
|
||||||
Ok(Type::new(IterT::new(ItersT::Enumerate, data)?))
|
Ok(Type::new(IterT::new(ItersT::Enumerate, data, i)?))
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
|
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
@ -150,13 +152,13 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
let data = if let Some(a) = a.iterable() {
|
let data = if let Some(a) = a.iterable() {
|
||||||
a
|
a
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("cannot call chain on non-iterable type {a}.").into());
|
return Err(format!("cannot call chain on non-iterable type {}.", a.with_info(i)).into());
|
||||||
};
|
};
|
||||||
Ok(Type::new(IterT::new(ItersT::Chained, data)?))
|
Ok(Type::new(IterT::new(ItersT::Chained, data, i)?))
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
|
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
@ -172,6 +174,7 @@ fn genfunc_iter_and_func(
|
|||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
fn iter_out_arg(
|
fn iter_out_arg(
|
||||||
a: &Type,
|
a: &Type,
|
||||||
|
i: &mut CheckInfo,
|
||||||
name: &str,
|
name: &str,
|
||||||
func: impl Fn(FunctionT) -> ItersT + Sync + Send,
|
func: impl Fn(FunctionT) -> ItersT + Sync + Send,
|
||||||
) -> Result<Type, CheckError> {
|
) -> Result<Type, CheckError> {
|
||||||
@ -184,14 +187,16 @@ fn genfunc_iter_and_func(
|
|||||||
if let Some(v) = t.0[0].iterable() {
|
if let Some(v) = t.0[0].iterable() {
|
||||||
for f in t.0[1].types.iter() {
|
for f in t.0[1].types.iter() {
|
||||||
if let Some(f) = f.executable() {
|
if let Some(f) = f.executable() {
|
||||||
out.add(Arc::new(IterT::new(func(f), v.clone())?));
|
out.add(Arc::new(IterT::new(func(f), v.clone(), i)?));
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {a}", t.0[1]).into());
|
return Err(format!("cannot call {name} on tuple that isn't (_, function): got {} instead of function as part of {}", t.0[1].with_info(i), a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"cannot call {name} on non-iterable type {t}, which is part of {a}."
|
"cannot call {name} on non-iterable type {}, which is part of {}.",
|
||||||
|
t.with_info(i),
|
||||||
|
a.with_info(i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -202,7 +207,7 @@ fn genfunc_iter_and_func(
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(move |a, _i| iter_out_arg(a, name, |f| ft(f)))),
|
out: Ok(Arc::new(move |a, i| iter_out_arg(a, i, name, |f| ft(f)))),
|
||||||
run: Arc::new(move |a, _i| {
|
run: Arc::new(move |a, _i| {
|
||||||
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
||||||
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
|
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
|
||||||
@ -225,10 +230,12 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
|
|||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
fn iter_out_arg<T: MersType>(
|
fn iter_out_arg<T: MersType>(
|
||||||
a: &Type,
|
a: &Type,
|
||||||
|
i: &mut CheckInfo,
|
||||||
name: &str,
|
name: &str,
|
||||||
func: impl Fn(&T) -> ItersT + Sync + Send,
|
func: impl Fn(&T) -> ItersT + Sync + Send,
|
||||||
type_sample: &T,
|
type_sample: &T,
|
||||||
) -> Result<Type, CheckError> {
|
) -> Result<Type, CheckError> {
|
||||||
|
let type_sample = type_sample.with_info(i);
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
@ -238,14 +245,16 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
|
|||||||
if let Some(v) = t.0[0].iterable() {
|
if let Some(v) = t.0[0].iterable() {
|
||||||
for f in t.0[1].types.iter() {
|
for f in t.0[1].types.iter() {
|
||||||
if let Some(f) = f.as_any().downcast_ref::<T>() {
|
if let Some(f) = f.as_any().downcast_ref::<T>() {
|
||||||
out.add(Arc::new(IterT::new(func(f), v.clone())?));
|
out.add(Arc::new(IterT::new(func(f), v.clone(), i)?));
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {a}", t.0[1]).into());
|
return Err(format!("cannot call {name} on tuple that isn't (_, {type_sample}): got {} instead of {type_sample} as part of {}", t.0[1].with_info(i), a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"cannot call {name} on non-iterable type {t}, which is part of {a}."
|
"cannot call {name} on non-iterable type {}, which is part of {}.",
|
||||||
|
t.with_info(i),
|
||||||
|
a.with_info(i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -256,8 +265,8 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(move |a, _i| {
|
out: Ok(Arc::new(move |a, i| {
|
||||||
iter_out_arg(a, name, |f: &T| ft(f), type_sample)
|
iter_out_arg(a, i, name, |f: &T| ft(f), type_sample)
|
||||||
})),
|
})),
|
||||||
run: Arc::new(move |a, _i| {
|
run: Arc::new(move |a, _i| {
|
||||||
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
||||||
@ -303,6 +312,9 @@ pub struct Iter(pub Iters, pub Data);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct IterT(pub ItersT, pub Type, pub Type);
|
pub struct IterT(pub ItersT, pub Type, pub Type);
|
||||||
impl MersData for Iter {
|
impl MersData for Iter {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, _other: &dyn MersData) -> bool {
|
fn is_eq(&self, _other: &dyn MersData) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -396,7 +408,14 @@ impl MersData for Iter {
|
|||||||
Box::new(Clone::clone(self))
|
Box::new(Clone::clone(self))
|
||||||
}
|
}
|
||||||
fn as_type(&self) -> data::Type {
|
fn as_type(&self) -> data::Type {
|
||||||
Type::new(IterT::new(self.0.as_type(), self.1.get().as_type()).unwrap())
|
Type::new(
|
||||||
|
IterT::new(
|
||||||
|
self.0.as_type(),
|
||||||
|
self.1.get().as_type(),
|
||||||
|
&crate::info::Info::neverused(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
@ -409,7 +428,8 @@ impl MersData for Iter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl IterT {
|
impl IterT {
|
||||||
pub fn new(iter: ItersT, data: Type) -> Result<Self, CheckError> {
|
/// `i` is only used for errors (this is important for `as_type()`)
|
||||||
|
pub fn new(iter: ItersT, data: Type, i: &CheckInfo) -> Result<Self, CheckError> {
|
||||||
let t = match &iter {
|
let t = match &iter {
|
||||||
ItersT::Map(f) => f.o(&data)?,
|
ItersT::Map(f) => f.o(&data)?,
|
||||||
ItersT::Filter(f) => {
|
ItersT::Filter(f) => {
|
||||||
@ -417,7 +437,8 @@ impl IterT {
|
|||||||
data.clone()
|
data.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Iter:Filter, but function doesn't return bool for argument {data}."
|
"Iter:Filter, but function doesn't return bool for argument {}.",
|
||||||
|
data.with_info(&i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -450,7 +471,8 @@ impl IterT {
|
|||||||
out
|
out
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Cannot create a chain from an iterator over the non-iterator type {data}."
|
"Cannot create a chain from an iterator over the non-iterator type {}.",
|
||||||
|
data.with_info(i)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -460,6 +482,13 @@ impl IterT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for IterT {
|
impl MersType for IterT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "<Iter: {}>", self.2.with_display(info))
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
self.2.is_same_type_as(&other.2)
|
self.2.is_same_type_as(&other.2)
|
||||||
@ -496,11 +525,6 @@ impl Display for Iter {
|
|||||||
write!(f, "<Iter>")
|
write!(f, "<Iter>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for IterT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "<Iter: {}>", self.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Iters {
|
impl Iters {
|
||||||
fn as_type(&self) -> ItersT {
|
fn as_type(&self) -> ItersT {
|
||||||
match self {
|
match self {
|
||||||
@ -527,15 +551,24 @@ fn genfunc_iter_in_val_out(
|
|||||||
Function {
|
Function {
|
||||||
info: crate::info::Info::neverused(),
|
info: crate::info::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
|
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
|
||||||
out: Ok(Arc::new(move |a, _i| {
|
out: Ok(Arc::new(move |a, i| {
|
||||||
if let Some(iter_over) = a.iterable() {
|
if let Some(iter_over) = a.iterable() {
|
||||||
if iter_over.is_included_in(&iter_type) {
|
if iter_over.is_included_in(&iter_type) {
|
||||||
Ok(out_type.clone())
|
Ok(out_type.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Cannot call function {name} on iterator over type {a}, which isn't {iter_type}.").into())
|
Err(format!(
|
||||||
|
"Cannot call function {name} on iterator over type {}, which isn't {}.",
|
||||||
|
a.with_info(i),
|
||||||
|
iter_type.with_info(i)
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Cannot call function {name} on non-iterable type {a}.").into())
|
Err(format!(
|
||||||
|
"Cannot call function {name} on non-iterable type {}.",
|
||||||
|
a.with_info(i)
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(run),
|
run: Arc::new(run),
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use std::{
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
fmt::Display,
|
|
||||||
sync::{Arc, Mutex, RwLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, MersType, Type},
|
data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
|
info::DisplayInfo,
|
||||||
parsing::{statements::to_string_literal, Source},
|
parsing::{statements::to_string_literal, Source},
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
@ -34,7 +32,7 @@ impl Config {
|
|||||||
.add_var("get_mut", data::function::Function {
|
.add_var("get_mut", data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
let mut out = Type::empty_tuple();
|
let mut out = Type::empty_tuple();
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
@ -50,18 +48,18 @@ impl Config {
|
|||||||
out.add(Arc::new(data::tuple::TupleT(vec![Type::new(data::reference::ReferenceT(t.0.clone()))])));
|
out.add(Arc::new(data::tuple::TupleT(vec![Type::new(data::reference::ReferenceT(t.0.clone()))])));
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"get_mut: first argument in tuple {t} isn't `&List<_>`."
|
"get_mut: first argument in tuple {} isn't `&List<_>`.", t.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"get_mut: first type in tuple {t} isn't a reference."
|
"get_mut: first type in tuple {} isn't a reference.", t.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"get_mut: Second type in tuple {t} wasn't `Int`."
|
"get_mut: Second type in tuple {} wasn't `Int`.", t.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -103,7 +101,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if let Some(a) = a.dereference() {
|
if let Some(a) = a.dereference() {
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
@ -111,7 +109,7 @@ impl Config {
|
|||||||
out.add_all(&t.0);
|
out.add_all(&t.0);
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"pop: found a reference to {t}, which is not a list"
|
"pop: found a reference to {}, which is not a list", t.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +118,7 @@ impl Config {
|
|||||||
Arc::new(data::tuple::TupleT(vec![]))
|
Arc::new(data::tuple::TupleT(vec![]))
|
||||||
]))
|
]))
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("pop: not a reference: {a}").into());
|
return Err(format!("pop: not a reference: {}", a.with_info(i)).into());
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
@ -151,7 +149,7 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
if t.0.len() != 2 {
|
if t.0.len() != 2 {
|
||||||
@ -166,22 +164,22 @@ impl Config {
|
|||||||
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
|
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
|
||||||
if !new.is_included_in(&t.0) {
|
if !new.is_included_in(&t.0) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"push: found a reference to {t}, which is a list which can't contain elements of type {new}"
|
"push: found a reference to {}, which is a list which can't contain elements of type {}", t.with_info(i), new.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"push: found a reference to {t}, which is not a list"
|
"push: found a reference to {}, which is not a list", t.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"push: first element in tuple not a reference: {a}"
|
"push: first element in tuple not a reference: {}", a.with_info(i)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("push: not a tuple: {t}")
|
return Err(format!("push: not a tuple: {}", t.with_info(i))
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,12 +212,12 @@ impl Config {
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
if let Some(v) = a.iterable() {
|
if let Some(v) = a.iterable() {
|
||||||
Ok(Type::new(ListT(v)))
|
Ok(Type::new(ListT(v)))
|
||||||
} else {
|
} else {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"cannot iterate over type {a}"
|
"cannot iterate over type {}", a.with_info(i)
|
||||||
).into())
|
).into())
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
@ -251,6 +249,17 @@ impl Clone for List {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ListT(pub Type);
|
pub struct ListT(pub Type);
|
||||||
impl MersData for List {
|
impl MersData for List {
|
||||||
|
fn display(&self, info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "[")?;
|
||||||
|
for (i, c) in self.0.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
c.read().unwrap().get().display(info, f)?;
|
||||||
|
}
|
||||||
|
write!(f, "]")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
other.0.len() == self.0.len()
|
other.0.len() == self.0.len()
|
||||||
@ -288,6 +297,17 @@ impl MersData for List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for ListT {
|
impl MersType for ListT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"List<{}>",
|
||||||
|
to_string_literal(&self.0.with_display(info).to_string(), '>')
|
||||||
|
)
|
||||||
|
}
|
||||||
fn iterable(&self) -> Option<Type> {
|
fn iterable(&self) -> Option<Type> {
|
||||||
Some(self.0.clone())
|
Some(self.0.clone())
|
||||||
}
|
}
|
||||||
@ -324,25 +344,6 @@ impl MersType for ListT {
|
|||||||
Some(Type::new(Self(self.0.simplify_for_display(info))))
|
Some(Type::new(Self(self.0.simplify_for_display(info))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for List {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "[")?;
|
|
||||||
for (i, c) in self.0.iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{}", c.read().unwrap().get())?;
|
|
||||||
}
|
|
||||||
write!(f, "]")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for ListT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "List<{}>", to_string_literal(&self.0.to_string(), '>'))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl List {
|
impl List {
|
||||||
pub fn inner_type(&self) -> Type {
|
pub fn inner_type(&self) -> Type {
|
||||||
let mut t = Type::empty();
|
let mut t = Type::empty();
|
||||||
|
@ -326,7 +326,7 @@ fn num_iter_to_num(
|
|||||||
data::function::Function {
|
data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(move |a, _i| {
|
out: Ok(Arc::new(move |a, i| {
|
||||||
if let Some(a) = a.iterable() {
|
if let Some(a) = a.iterable() {
|
||||||
let int_type = Type::new(data::int::IntT);
|
let int_type = Type::new(data::int::IntT);
|
||||||
if a.is_included_in(&int_type) {
|
if a.is_included_in(&int_type) {
|
||||||
@ -343,7 +343,7 @@ fn num_iter_to_num(
|
|||||||
if a.is_included_in(&int_float_type) {
|
if a.is_included_in(&int_float_type) {
|
||||||
Ok(int_float_type)
|
Ok(int_float_type)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("argument passed to {func_name} must be an iterator over values of type Int/String, but was an iterator over values of type {a}.").into())
|
Err(format!("argument passed to {func_name} must be an iterator over values of type Int/String, but was an iterator over values of type {}.", a.with_info(i)).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, MersType, Type},
|
data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
|
info::DisplayInfo,
|
||||||
parsing::{statements::to_string_literal, Source},
|
parsing::{statements::to_string_literal, Source},
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
@ -57,10 +58,10 @@ impl Config {
|
|||||||
.add_var("thread_finished", data::function::Function {
|
.add_var("thread_finished", data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if !t.as_any().is::<ThreadT>() {
|
if !t.as_any().is::<ThreadT>() {
|
||||||
return Err(CheckError::new().msg_str(format!("Cannot call thread_finished on a value of type {t}, which isn't a thread but part of the argument {a}.")));
|
return Err(CheckError::new().msg_str(format!("Cannot call thread_finished on a value of type {}, which isn't a thread but part of the argument {}.", t.with_info(i), a.with_info(i))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(data::bool::bool_type())
|
Ok(data::bool::bool_type())
|
||||||
@ -78,13 +79,13 @@ impl Config {
|
|||||||
.add_var("thread_await", data::function::Function {
|
.add_var("thread_await", data::function::Function {
|
||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
out: Ok(Arc::new(|a, i| {
|
||||||
let mut out = Type::empty();
|
let mut out = Type::empty();
|
||||||
for t in a.types.iter() {
|
for t in a.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<ThreadT>() {
|
if let Some(t) = t.as_any().downcast_ref::<ThreadT>() {
|
||||||
out.add_all(&t.0);
|
out.add_all(&t.0);
|
||||||
} else {
|
} else {
|
||||||
return Err(CheckError::new().msg_str(format!("Cannot call thread_await on a value of type {t}, which isn't a thread but part of the argument {a}.")));
|
return Err(CheckError::new().msg_str(format!("Cannot call thread_await on a value of type {}, which isn't a thread but part of the argument {}.", t.with_info(i), a.with_info(i))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(out)
|
Ok(out)
|
||||||
@ -112,6 +113,9 @@ pub struct Thread(
|
|||||||
pub struct ThreadT(pub Type);
|
pub struct ThreadT(pub Type);
|
||||||
|
|
||||||
impl MersData for Thread {
|
impl MersData for Thread {
|
||||||
|
fn display(&self, _info: &DisplayInfo<'_>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
fn is_eq(&self, _other: &dyn MersData) -> bool {
|
fn is_eq(&self, _other: &dyn MersData) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -132,6 +136,17 @@ impl MersData for Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MersType for ThreadT {
|
impl MersType for ThreadT {
|
||||||
|
fn display(
|
||||||
|
&self,
|
||||||
|
info: &crate::info::DisplayInfo<'_>,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Thread<{}>",
|
||||||
|
to_string_literal(&self.0.with_display(info).to_string(), '>')
|
||||||
|
)
|
||||||
|
}
|
||||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||||
self.0.is_same_type_as(&other.0)
|
self.0.is_same_type_as(&other.0)
|
||||||
@ -172,8 +187,3 @@ impl Display for Thread {
|
|||||||
write!(f, "<Thread>")
|
write!(f, "<Thread>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for ThreadT {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Thread<{}>", to_string_literal(&self.0.to_string(), '>'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, MersDataWInfo, Type},
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,9 +66,9 @@ impl Config {
|
|||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
|
out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
let a2 = a.get();
|
let a2 = a.get();
|
||||||
eprintln!("{} :: {}", a2.as_type(), a2);
|
eprintln!("{} :: {}", a2.as_type().with_info(i), a2.with_info(i));
|
||||||
drop(a2);
|
drop(a2);
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}),
|
}),
|
||||||
@ -81,8 +81,8 @@ impl Config {
|
|||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
eprint!("{}", a.get());
|
eprint!("{}", a.get().with_info(i));
|
||||||
_ = std::io::stderr().lock().flush();
|
_ = std::io::stderr().lock().flush();
|
||||||
Ok(Data::empty_tuple())
|
Ok(Data::empty_tuple())
|
||||||
}),
|
}),
|
||||||
@ -95,8 +95,8 @@ impl Config {
|
|||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
eprintln!("{}", a.get());
|
eprintln!("{}", a.get().with_info(i));
|
||||||
Ok(Data::empty_tuple())
|
Ok(Data::empty_tuple())
|
||||||
}),
|
}),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
@ -108,8 +108,8 @@ impl Config {
|
|||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
print!("{}", a.get());
|
print!("{}", a.get().with_info(i));
|
||||||
_ = std::io::stdout().lock().flush();
|
_ = std::io::stdout().lock().flush();
|
||||||
Ok(Data::empty_tuple())
|
Ok(Data::empty_tuple())
|
||||||
}),
|
}),
|
||||||
@ -122,8 +122,8 @@ impl Config {
|
|||||||
info: program::run::Info::neverused(),
|
info: program::run::Info::neverused(),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, i| {
|
||||||
println!("{}", a.get());
|
println!("{}", a.get().with_info(i));
|
||||||
Ok(Data::empty_tuple())
|
Ok(Data::empty_tuple())
|
||||||
}),
|
}),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::data::{self, Data, Type};
|
use crate::data::{self, Data, MersDataWInfo, Type};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
gen::{function::func, AnyOrNone, IterToList, OneOf, OneOrNone},
|
gen::{function::func, AnyOrNone, IterToList, OneOf, OneOrNone},
|
||||||
@ -58,19 +58,22 @@ impl Config {
|
|||||||
.add_var(
|
.add_var(
|
||||||
"concat",
|
"concat",
|
||||||
util::to_mers_func(
|
util::to_mers_func(
|
||||||
|a| {
|
|a, i| {
|
||||||
if a.iterable().is_some() {
|
if a.iterable().is_some() {
|
||||||
Ok(Type::new(data::string::StringT))
|
Ok(Type::new(data::string::StringT))
|
||||||
} else {
|
} else {
|
||||||
Err(format!("concat called on non-iterable type {a}").into())
|
Err(
|
||||||
|
format!("concat called on non-iterable type {}", a.with_info(i))
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|a| {
|
|a, i| {
|
||||||
Ok(Data::new(data::string::String(
|
Ok(Data::new(data::string::String(
|
||||||
a.get()
|
a.get()
|
||||||
.iterable()
|
.iterable()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|v| v.map(|v| v.get().to_string()))
|
.map(|v| v.map(|v| v.get().with_info(i).to_string()))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
)))
|
)))
|
||||||
},
|
},
|
||||||
@ -79,8 +82,12 @@ impl Config {
|
|||||||
.add_var(
|
.add_var(
|
||||||
"to_string",
|
"to_string",
|
||||||
util::to_mers_func(
|
util::to_mers_func(
|
||||||
|_a| Ok(Type::new(data::string::StringT)),
|
|_a, _| Ok(Type::new(data::string::StringT)),
|
||||||
|a| Ok(Data::new(data::string::String(a.get().to_string()))),
|
|a, i| {
|
||||||
|
Ok(Data::new(data::string::String(
|
||||||
|
a.get().with_info(i).to_string(),
|
||||||
|
)))
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
|
@ -3,9 +3,9 @@ use std::sync::{Arc, Mutex};
|
|||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data},
|
data::{self, Data},
|
||||||
errors::{CheckError, EColor, SourceRange},
|
errors::{CheckError, EColor, SourceRange},
|
||||||
info::{self, Local},
|
info,
|
||||||
parsing::Source,
|
parsing::Source,
|
||||||
program::{self},
|
program,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{CheckError, SourceRange},
|
errors::{CheckError, SourceRange},
|
||||||
info,
|
info::{self, DisplayInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
@ -113,7 +113,7 @@ pub struct Local {
|
|||||||
pub vars: HashMap<String, (usize, usize)>,
|
pub vars: HashMap<String, (usize, usize)>,
|
||||||
pub vars_count: usize,
|
pub vars_count: usize,
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LocalGlobalInfo {
|
pub struct LocalGlobalInfo {
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub enable_hooks: bool,
|
pub enable_hooks: bool,
|
||||||
@ -129,11 +129,33 @@ pub struct LocalGlobalInfo {
|
|||||||
)>,
|
)>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
|
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
|
||||||
|
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
|
||||||
|
}
|
||||||
|
impl LocalGlobalInfo {
|
||||||
|
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
depth: 0,
|
||||||
|
enable_hooks: false,
|
||||||
|
save_info_at: Default::default(),
|
||||||
|
object_fields,
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl info::Local for Local {
|
impl info::Local for Local {
|
||||||
type VariableIdentifier = String;
|
type VariableIdentifier = String;
|
||||||
type VariableData = (usize, usize);
|
type VariableData = (usize, usize);
|
||||||
type Global = LocalGlobalInfo;
|
type Global = LocalGlobalInfo;
|
||||||
|
fn neverused_global() -> Self::Global {
|
||||||
|
Self::Global {
|
||||||
|
depth: 0,
|
||||||
|
enable_hooks: false,
|
||||||
|
save_info_at: Default::default(),
|
||||||
|
object_fields: Default::default(),
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
||||||
self.vars_count += 1;
|
self.vars_count += 1;
|
||||||
self.vars.insert(id, value);
|
self.vars.insert(id, value);
|
||||||
@ -147,4 +169,10 @@ impl info::Local for Local {
|
|||||||
fn duplicate(&self) -> Self {
|
fn duplicate(&self) -> Self {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
|
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
|
||||||
|
DisplayInfo {
|
||||||
|
object_fields: &global.object_fields,
|
||||||
|
object_fields_rev: &global.object_fields_rev,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
data::object::ObjectFieldsMap,
|
||||||
errors::{CheckError, SourceRange},
|
errors::{CheckError, SourceRange},
|
||||||
info,
|
info, program,
|
||||||
program::{self},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
@ -22,10 +22,15 @@ impl MersStatement for Object {
|
|||||||
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
|
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
|
||||||
Ok(Box::new(program::run::object::Object {
|
Ok(Box::new(program::run::object::Object {
|
||||||
pos_in_src: self.pos_in_src.clone(),
|
pos_in_src: self.pos_in_src.clone(),
|
||||||
elems: self
|
fields: self
|
||||||
.elems
|
.elems
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, v)| -> Result<_, CheckError> { Ok((n.clone(), v.compile(info, comp)?)) })
|
.map(|(n, v)| -> Result<_, CheckError> {
|
||||||
|
Ok((
|
||||||
|
info.global.object_fields.get_or_add_field(n),
|
||||||
|
v.compile(info, comp)?,
|
||||||
|
))
|
||||||
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{CheckError, EColor, SourceRange},
|
errors::{CheckError, EColor, SourceRange},
|
||||||
info::Local,
|
program,
|
||||||
program::{self},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, Type},
|
data::{self, Data, MersData, Type},
|
||||||
errors::{CheckError, SourceRange},
|
errors::{CheckError, SourceRange},
|
||||||
info::Local,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::MersStatement;
|
use super::MersStatement;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, MersTypeWInfo, Type},
|
||||||
errors::{CheckError, SourceRange},
|
errors::{CheckError, SourceRange},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ impl MersStatement for Loop {
|
|||||||
if let Some(i) = i.as_any().downcast_ref::<data::tuple::TupleT>() {
|
if let Some(i) = i.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
if i.0.len() > 1 {
|
if i.0.len() > 1 {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Loop: Inner statement must return ()/(T), not {t} (because of {i}, a tuple of length > 1)."
|
"Loop: Inner statement must return ()/(T), not {} (because of {}, a tuple of length > 1).", t.with_info(info), i.with_info(info)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
} else {
|
} else {
|
||||||
@ -40,7 +40,7 @@ impl MersStatement for Loop {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Loop: Inner statement must return ()/(T), not {t} (because of {i}, which isn't a tuple)."
|
"Loop: Inner statement must return ()/(T), not {} (because of {}, which isn't a tuple).", t.with_info(info), i.with_info(info)
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use std::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, Type},
|
||||||
errors::{CheckError, EColor, SourceRange},
|
errors::{CheckError, EColor, SourceRange},
|
||||||
info,
|
info::{self, DisplayInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
@ -126,10 +126,21 @@ pub type CheckInfo = info::Info<CheckLocal>;
|
|||||||
pub struct RunLocal {
|
pub struct RunLocal {
|
||||||
pub vars: Vec<Arc<RwLock<Data>>>,
|
pub vars: Vec<Arc<RwLock<Data>>>,
|
||||||
}
|
}
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RunLocalGlobalInfo {
|
pub struct RunLocalGlobalInfo {
|
||||||
/// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error.
|
/// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error.
|
||||||
pub limit_runtime: Option<Instant>,
|
pub limit_runtime: Option<Instant>,
|
||||||
|
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
|
||||||
|
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
|
||||||
|
}
|
||||||
|
impl RunLocalGlobalInfo {
|
||||||
|
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
limit_runtime: None,
|
||||||
|
object_fields,
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct CheckLocal {
|
pub struct CheckLocal {
|
||||||
@ -142,7 +153,7 @@ pub struct CheckLocal {
|
|||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone)]
|
||||||
pub struct CheckLocalGlobalInfo {
|
pub struct CheckLocalGlobalInfo {
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub enable_hooks: bool,
|
pub enable_hooks: bool,
|
||||||
@ -160,6 +171,8 @@ pub struct CheckLocalGlobalInfo {
|
|||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>,
|
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>,
|
||||||
|
pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
|
||||||
|
pub object_fields_rev: Arc<Mutex<Vec<String>>>,
|
||||||
}
|
}
|
||||||
impl CheckLocalGlobalInfo {
|
impl CheckLocalGlobalInfo {
|
||||||
pub fn show_warnings_to_stderr(&mut self) {
|
pub fn show_warnings_to_stderr(&mut self) {
|
||||||
@ -171,6 +184,18 @@ impl CheckLocalGlobalInfo {
|
|||||||
eprintln!("{}", e.display(theme));
|
eprintln!("{}", e.display(theme));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
depth: 0,
|
||||||
|
enable_hooks: false,
|
||||||
|
show_warnings: None,
|
||||||
|
save_info_at: Default::default(),
|
||||||
|
unused_try_statements: Default::default(),
|
||||||
|
object_fields,
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Debug for CheckLocalGlobalInfo {
|
impl Debug for CheckLocalGlobalInfo {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@ -186,6 +211,13 @@ impl info::Local for RunLocal {
|
|||||||
type VariableIdentifier = usize;
|
type VariableIdentifier = usize;
|
||||||
type VariableData = Arc<RwLock<Data>>;
|
type VariableData = Arc<RwLock<Data>>;
|
||||||
type Global = RunLocalGlobalInfo;
|
type Global = RunLocalGlobalInfo;
|
||||||
|
fn neverused_global() -> Self::Global {
|
||||||
|
Self::Global {
|
||||||
|
limit_runtime: None,
|
||||||
|
object_fields: Default::default(),
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
||||||
let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
|
let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
|
||||||
while self.vars.len() <= id {
|
while self.vars.len() <= id {
|
||||||
@ -214,11 +246,28 @@ impl info::Local for RunLocal {
|
|||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
|
||||||
|
DisplayInfo {
|
||||||
|
object_fields: &global.object_fields,
|
||||||
|
object_fields_rev: &global.object_fields_rev,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl info::Local for CheckLocal {
|
impl info::Local for CheckLocal {
|
||||||
type VariableIdentifier = usize;
|
type VariableIdentifier = usize;
|
||||||
type VariableData = Type;
|
type VariableData = Type;
|
||||||
type Global = CheckLocalGlobalInfo;
|
type Global = CheckLocalGlobalInfo;
|
||||||
|
fn neverused_global() -> Self::Global {
|
||||||
|
Self::Global {
|
||||||
|
depth: 0,
|
||||||
|
enable_hooks: false,
|
||||||
|
show_warnings: None,
|
||||||
|
save_info_at: Default::default(),
|
||||||
|
unused_try_statements: Default::default(),
|
||||||
|
object_fields: Default::default(),
|
||||||
|
object_fields_rev: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
|
||||||
while self.vars.len() <= id {
|
while self.vars.len() <= id {
|
||||||
self.vars.push(Type::empty());
|
self.vars.push(Type::empty());
|
||||||
@ -240,4 +289,10 @@ impl info::Local for CheckLocal {
|
|||||||
fn duplicate(&self) -> Self {
|
fn duplicate(&self) -> Self {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
|
fn display_info<'a>(global: &'a Self::Global) -> DisplayInfo<'a> {
|
||||||
|
DisplayInfo {
|
||||||
|
object_fields: &global.object_fields,
|
||||||
|
object_fields_rev: &global.object_fields_rev,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, object::ObjectT, Data, MersType, Type},
|
data::{self, object::ObjectT, Data, Type},
|
||||||
errors::{CheckError, EColor, SourceRange},
|
errors::{CheckError, EColor, SourceRange},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ use super::MersStatement;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub pos_in_src: SourceRange,
|
pub pos_in_src: SourceRange,
|
||||||
pub elems: Vec<(String, Box<dyn MersStatement>)>,
|
pub fields: Vec<(usize, Box<dyn MersStatement>)>,
|
||||||
}
|
}
|
||||||
impl MersStatement for Object {
|
impl MersStatement for Object {
|
||||||
fn check_custom(
|
fn check_custom(
|
||||||
@ -18,75 +18,16 @@ impl MersStatement for Object {
|
|||||||
info: &mut super::CheckInfo,
|
info: &mut super::CheckInfo,
|
||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<data::Type, super::CheckError> {
|
) -> Result<data::Type, super::CheckError> {
|
||||||
let mut assign_types = if let Some(init_to) = init_to {
|
let mut init_fields = if let Some(init_to) = init_to {
|
||||||
let mut acc = (0..self.elems.len())
|
|
||||||
.map(|_| Type::empty())
|
|
||||||
.collect::<VecDeque<_>>();
|
|
||||||
let print_is_part_of = init_to.types.len() > 1;
|
let print_is_part_of = init_to.types.len() > 1;
|
||||||
|
let mut init_fields = HashMap::new();
|
||||||
for t in init_to.types.iter() {
|
for t in init_to.types.iter() {
|
||||||
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
|
if let Some(t) = t.as_any().downcast_ref::<ObjectT>() {
|
||||||
if self.elems.len() == t.0.len() {
|
for (field, t) in t.iter() {
|
||||||
for (i, ((sn, _), (tn, t))) in self.elems.iter().zip(t.0.iter()).enumerate()
|
init_fields
|
||||||
{
|
.entry(*field)
|
||||||
if sn != tn {
|
.or_insert_with(Type::empty)
|
||||||
return Err(CheckError::new().msg(vec![
|
.add_all(t);
|
||||||
("can't init an ".to_owned(), None),
|
|
||||||
("object".to_owned(), Some(EColor::InitTo)),
|
|
||||||
(" with type ".to_owned(), None),
|
|
||||||
(t.simplified_as_string(info), Some(EColor::InitFrom)),
|
|
||||||
if print_is_part_of {
|
|
||||||
(", which is part of ".to_owned(), None)
|
|
||||||
} else {
|
|
||||||
(String::new(), None)
|
|
||||||
},
|
|
||||||
if print_is_part_of {
|
|
||||||
(init_to.simplified_as_string(info), Some(EColor::InitFrom))
|
|
||||||
} else {
|
|
||||||
(String::new(), None)
|
|
||||||
},
|
|
||||||
(" - field mismatch: ".to_owned(), None),
|
|
||||||
(sn.to_owned(), None),
|
|
||||||
(" != ".to_owned(), None),
|
|
||||||
(tn.to_owned(), None),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
acc[i].add_all(&t);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(CheckError::new().msg(vec![
|
|
||||||
("can't init an ".to_owned(), None),
|
|
||||||
("object".to_owned(), Some(EColor::InitTo)),
|
|
||||||
(" with type ".to_owned(), None),
|
|
||||||
(t.simplified_as_string(info), Some(EColor::InitFrom)),
|
|
||||||
if print_is_part_of {
|
|
||||||
(", which is part of ".to_owned(), None)
|
|
||||||
} else {
|
|
||||||
(format!(""), None)
|
|
||||||
},
|
|
||||||
if print_is_part_of {
|
|
||||||
(init_to.simplified_as_string(info), Some(EColor::InitFrom))
|
|
||||||
} else {
|
|
||||||
(format!(""), None)
|
|
||||||
},
|
|
||||||
(" - source has ".to_owned(), None),
|
|
||||||
(if self.elems.len() > t.0.len() {
|
|
||||||
format!("less fields ({}, not {})", t.0.len(), self.elems.len())
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"more fields. Either ignore those fields (`{}`) - or remove them from the type (`... := [{}] ...`)",
|
|
||||||
t.0.iter()
|
|
||||||
.skip(self.elems.len())
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, (n, _))| if i == 0 {
|
|
||||||
format!("{n}: _")
|
|
||||||
} else {
|
|
||||||
format!(", {n}: _")
|
|
||||||
})
|
|
||||||
.collect::<String>(),
|
|
||||||
data::object::ObjectT(t.0.iter().take(self.elems.len()).cloned().collect()).simplified_as_string(info)
|
|
||||||
)
|
|
||||||
}, None)
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(CheckError::new().msg(vec![
|
return Err(CheckError::new().msg(vec![
|
||||||
@ -111,20 +52,39 @@ impl MersStatement for Object {
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(acc)
|
Some(init_fields)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(Type::new(data::object::ObjectT(
|
Ok(Type::new(data::object::ObjectT::new(
|
||||||
self.elems
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, v)| -> Result<_, CheckError> {
|
.map(|(field, v)| -> Result<_, CheckError> {
|
||||||
Ok((
|
Ok((
|
||||||
n.clone(),
|
*field,
|
||||||
v.check(
|
v.check(
|
||||||
info,
|
info,
|
||||||
if let Some(it) = &mut assign_types {
|
if let Some(f) = &mut init_fields {
|
||||||
Some(it.pop_front().unwrap())
|
Some(if let Some(s) = f.remove(field) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
return Err(CheckError::new().msg(vec![
|
||||||
|
("can't init an ".to_owned(), None),
|
||||||
|
("object".to_owned(), Some(EColor::InitTo)),
|
||||||
|
(" with type ".to_owned(), None),
|
||||||
|
(
|
||||||
|
init_to.as_ref().unwrap().simplified_as_string(info),
|
||||||
|
Some(EColor::InitFrom),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
format!(
|
||||||
|
" - field {} is missing",
|
||||||
|
info.display_info().get_object_field_name(*field)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
]));
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -136,8 +96,8 @@ impl MersStatement for Object {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
|
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
|
||||||
Ok(Data::new(data::object::Object(
|
Ok(Data::new(data::object::Object::new(
|
||||||
self.elems
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?)))
|
.map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?)))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
@ -150,7 +110,7 @@ impl MersStatement for Object {
|
|||||||
self.pos_in_src.clone()
|
self.pos_in_src.clone()
|
||||||
}
|
}
|
||||||
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
|
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
|
||||||
self.elems.iter().map(|(_, s)| s.as_ref()).collect()
|
self.fields.iter().map(|(_, s)| s.as_ref()).collect()
|
||||||
}
|
}
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
|
@ -66,7 +66,7 @@ impl MersStatement for Try {
|
|||||||
"try: #{} is not a function, type is {} within {}.",
|
"try: #{} is not a function, type is {} within {}.",
|
||||||
i + 1,
|
i + 1,
|
||||||
ft.simplified_as_string(info),
|
ft.simplified_as_string(info),
|
||||||
func.simplify_for_display(info),
|
func.simplify_for_display(info).with_info(info),
|
||||||
))
|
))
|
||||||
.src(vec![
|
.src(vec![
|
||||||
(self.source_range(), None),
|
(self.source_range(), None),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{fmt::Debug, sync::Arc};
|
use std::{fmt::Debug, sync::Arc};
|
||||||
|
|
||||||
|
use mers_lib::data::MersDataWInfo;
|
||||||
use mers_lib::prelude_compile::*;
|
use mers_lib::prelude_compile::*;
|
||||||
|
|
||||||
use mers_lib::{
|
use mers_lib::{
|
||||||
@ -15,7 +16,8 @@ fn variable() -> Res {
|
|||||||
run_code(Config::new(), format!("x := {n}, x"))?,
|
run_code(Config::new(), format!("x := {n}, x"))?,
|
||||||
TypedData(
|
TypedData(
|
||||||
Type::new(data::int::IntT),
|
Type::new(data::int::IntT),
|
||||||
Data::new(data::int::Int(n as _))
|
Data::new(data::int::Int(n as _)),
|
||||||
|
mers_lib::info::Info::neverused(),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -26,7 +28,11 @@ fn variable() -> Res {
|
|||||||
fn mutating_a_variable() -> Res {
|
fn mutating_a_variable() -> Res {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run_code(Config::new(), "x := 5, &x = 2, x")?,
|
run_code(Config::new(), "x := 5, &x = 2, x")?,
|
||||||
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(2)))
|
TypedData(
|
||||||
|
Type::new(data::int::IntT),
|
||||||
|
Data::new(data::int::Int(2)),
|
||||||
|
mers_lib::info::Info::neverused()
|
||||||
|
),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -35,7 +41,11 @@ fn mutating_a_variable() -> Res {
|
|||||||
fn variable_shadowing() -> Res {
|
fn variable_shadowing() -> Res {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run_code(Config::new(), "x := 5, { x := 2, &x = 3 }, x")?,
|
run_code(Config::new(), "x := 5, { x := 2, &x = 3 }, x")?,
|
||||||
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(5)))
|
TypedData(
|
||||||
|
Type::new(data::int::IntT),
|
||||||
|
Data::new(data::int::Int(5)),
|
||||||
|
mers_lib::info::Info::neverused()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -44,7 +54,11 @@ fn variable_shadowing() -> Res {
|
|||||||
fn identity_function() -> Res {
|
fn identity_function() -> Res {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run_code(Config::new(), "id := x -> x, 4.id")?,
|
run_code(Config::new(), "id := x -> x, 4.id")?,
|
||||||
TypedData(Type::new(data::int::IntT), Data::new(data::int::Int(4)))
|
TypedData(
|
||||||
|
Type::new(data::int::IntT),
|
||||||
|
Data::new(data::int::Int(4)),
|
||||||
|
mers_lib::info::Info::neverused()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -59,13 +73,18 @@ fn run_code(cfg: Config, code: impl Into<String>) -> Result<TypedData, CheckErro
|
|||||||
let compiled = parsed.compile(&mut i1, Default::default())?;
|
let compiled = parsed.compile(&mut i1, Default::default())?;
|
||||||
let output_type = compiled.check(&mut i3, Default::default())?;
|
let output_type = compiled.check(&mut i3, Default::default())?;
|
||||||
let output_data = compiled.run(&mut i2)?;
|
let output_data = compiled.run(&mut i2)?;
|
||||||
Ok(TypedData(output_type, output_data))
|
Ok(TypedData(output_type, output_data, i2))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypedData(Type, Data);
|
struct TypedData(Type, Data, mers_lib::program::run::Info);
|
||||||
impl Debug for TypedData {
|
impl Debug for TypedData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "Type: {}, Data: {}", self.0, self.1.get())
|
write!(
|
||||||
|
f,
|
||||||
|
"Type: {}, Data: {}",
|
||||||
|
self.0.with_info(&self.2),
|
||||||
|
self.1.get().with_info(&self.2)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PartialEq for TypedData {
|
impl PartialEq for TypedData {
|
||||||
@ -75,16 +94,16 @@ impl PartialEq for TypedData {
|
|||||||
let d1 = self.1 == other.1;
|
let d1 = self.1 == other.1;
|
||||||
let d2 = other.1 == self.1;
|
let d2 = other.1 == self.1;
|
||||||
if t1 && !t2 {
|
if t1 && !t2 {
|
||||||
panic!("self is same type as other, but other is not same type as self (non-symmetrical eq)! self={}, other={}", self.0, other.0);
|
panic!("self is same type as other, but other is not same type as self (non-symmetrical eq)! self={}, other={}", self.0.with_info(&self.2), other.0.with_info(&self.2));
|
||||||
}
|
}
|
||||||
if t2 && !t1 {
|
if t2 && !t1 {
|
||||||
panic!("other is same type as self, but self is not same type as other (non-symmetrical eq)! other={}, self={}", other.0, self.0);
|
panic!("other is same type as self, but self is not same type as other (non-symmetrical eq)! other={}, self={}", other.0.with_info(&self.2), self.0.with_info(&self.2));
|
||||||
}
|
}
|
||||||
if d1 && !d2 {
|
if d1 && !d2 {
|
||||||
panic!("self is same data as other, but other is not same data as self (non-symmetrical eq)! self={}, other={}", self.1.get(), other.1.get());
|
panic!("self is same data as other, but other is not same data as self (non-symmetrical eq)! self={}, other={}", self.1.get().with_info(&self.2), other.1.get().with_info(&self.2));
|
||||||
}
|
}
|
||||||
if d2 && !d1 {
|
if d2 && !d1 {
|
||||||
panic!("other is same data as self, but self is not same data as other (non-symmetrical eq)! other={}, self={}", other.1.get(), self.1.get());
|
panic!("other is same data as self, but self is not same data as other (non-symmetrical eq)! other={}, self={}", other.1.get().with_info(&self.2), self.1.get().with_info(&self.2));
|
||||||
}
|
}
|
||||||
t1 && d1
|
t1 && d1
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user