improve .try resolving types, removes subtypes methods
Some checks failed
Rust / build (push) Has been cancelled

This commit is contained in:
Mark 2025-07-15 14:53:54 +02:00
parent ac6b405a3c
commit 35efae75ac
24 changed files with 533 additions and 193 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "mers"
version = "0.9.22"
version = "0.9.23"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "dynamically typed but type-checked programming language"
@ -15,7 +15,7 @@ default = ["colored-output"]
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
[dependencies]
mers_lib = "0.9.22"
mers_lib = "0.9.23"
# mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true }

View File

@ -1,6 +1,6 @@
[package]
name = "mers_lib"
version = "0.9.22"
version = "0.9.23"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "library to use the mers language in other projects"

View File

@ -61,8 +61,12 @@ impl MersType for TrueT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self
@ -88,8 +92,12 @@ impl MersType for FalseT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -1,4 +1,4 @@
use std::{any::Any, fmt::Display, sync::Arc};
use std::{any::Any, fmt::Display};
use crate::info::DisplayInfo;
@ -51,8 +51,12 @@ impl MersType for ByteT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -1,4 +1,4 @@
use std::{any::Any, fmt::Display, sync::Arc};
use std::{any::Any, fmt::Display};
use crate::info::DisplayInfo;
@ -51,8 +51,12 @@ impl MersType for FloatT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -7,6 +7,7 @@ use std::{
use crate::{
errors::CheckError,
info::DisplayInfo,
parsing::types::ParsedType,
program::run::{CheckInfo, Info},
};
@ -15,6 +16,8 @@ use super::{Data, MersData, MersType, Type};
pub struct Function {
pub info: Info,
pub info_check: Arc<Mutex<CheckInfo>>,
pub fixed_type: Option<Vec<(Vec<ParsedType>, Option<Vec<ParsedType>>)>>,
pub fixed_type_out: Arc<Mutex<Option<Result<Arc<Vec<(Type, Type)>>, CheckError>>>>,
pub out: Result<
Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
Arc<Vec<(Type, Type)>>,
@ -31,6 +34,8 @@ impl Clone for Function {
Self {
info: self.info.duplicate(),
info_check: self.info_check.clone(),
fixed_type: self.fixed_type.clone(),
fixed_type_out: self.fixed_type_out.clone(),
out: self.out.clone(),
run: self.run.clone(),
inner_statements: self.inner_statements.clone(),
@ -45,6 +50,8 @@ impl Function {
Self {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Err(Arc::new(out)),
run: Arc::new(run),
inner_statements: None,
@ -57,6 +64,8 @@ impl Function {
Self {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| out(a, i))),
run: Arc::new(run),
inner_statements: None,
@ -66,6 +75,8 @@ impl Function {
Self {
info,
info_check: Arc::clone(&self.info_check),
fixed_type: self.fixed_type.clone(),
fixed_type_out: self.fixed_type_out.clone(),
out: self.out.clone(),
run: Arc::clone(&self.run),
inner_statements: self
@ -75,11 +86,56 @@ impl Function {
}
}
pub fn with_info_check(&self, check: CheckInfo) {
if let Some(fixed_type) = &self.fixed_type {
if let Ok(out_func) = &self.out {
let mut nout = Ok(Vec::with_capacity(fixed_type.len()));
for (in_type, out_type) in fixed_type {
if let Ok(new_out) = &mut nout {
let in_type = crate::parsing::types::type_from_parsed(in_type, &check)
.expect("failed to get intype from parsed type");
let out_type_want = out_type.as_ref().map(|out_type| {
crate::parsing::types::type_from_parsed(out_type, &check)
.expect("failed to get intype from parsed type")
});
let mut out_type = match out_func(&in_type, &mut check.clone()) {
Ok(t) => t,
Err(e) => {
nout = Err(e);
break;
}
};
if let Some(out_type_want) = out_type_want {
if out_type.is_included_in(&out_type_want) {
out_type = out_type_want;
} else {
nout = Err(format!(
"function must return {} for input {} because of its definition, but it returns {}.",
out_type_want.with_info(&check),
in_type.with_info(&check),
out_type.with_info(&check),
)
.into());
break;
}
}
new_out.push((in_type, out_type));
} else {
break;
}
}
*self.fixed_type_out.lock().unwrap() = Some(nout.map(Arc::new));
}
}
*self.info_check.lock().unwrap() = check;
}
pub fn check(&self, arg: &Type) -> Result<Type, CheckError> {
// TODO: this should require a CheckInfo and call `with_info_check`.
self.get_as_type().o(arg)
}
pub fn check_try(&self, arg: &Type) -> Result<Type, (CheckError, Vec<(Type, Type)>)> {
// TODO: this should require a CheckInfo and call `with_info_check`.
self.get_as_type().o_try(arg)
}
pub fn run_mut(
&mut self,
arg: Data,
@ -102,6 +158,19 @@ impl Function {
}
pub fn get_as_type(&self) -> FunctionT {
let info = self.info_check.lock().unwrap().clone();
if self.fixed_type.is_some() {
match &*self.fixed_type_out.lock().unwrap() {
Some(Ok(types)) => return FunctionT(Err(types.clone()), info),
Some(Err(e)) => {
let e = e.clone();
return FunctionT(
Ok(Arc::new(move |_, _| Err(e.clone()))),
crate::info::Info::neverused(),
);
}
_ => {}
}
}
match &self.out {
Ok(out) => {
let out = Arc::clone(out);
@ -189,13 +258,26 @@ pub struct FunctionT(
impl FunctionT {
/// get output type
pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
self.o_try(i).map_err(|(e, _)| e)
}
/// get output type
pub fn o_try(&self, i: &Type) -> Result<Type, (CheckError, Vec<(Type, Type)>)> {
match &self.0 {
Ok(f) => f(i, &self.1),
Ok(f) => f(i, &self.1).map_err(|e| (e, vec![])),
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()),
.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(),
v.iter()
.filter(|(a, _)| i.types.iter().any(|i| a.types.iter().any(|a|
i.without(a.as_ref()).is_some())))
.map(|(a, o)| (a.clone(), o.clone()))
.collect()
)
),
}
}
}
@ -280,8 +362,12 @@ impl MersType for FunctionT {
false
}
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -96,27 +96,35 @@ impl MersType for IntT {
false
}
}
fn subtypes(&self, acc: &mut Type) {
// INT_MIN .. INT32U_MIN .. INT32S_MIN .. -128 .. -1 .. 0 .. 1 .. 127 .. 255 .. 65535 .. INT32S_MAX .. INT32U_MAX .. INT_MAX
let mut add_range = |min, max| {
// the range is non-empty, self starts before or where the range ends, and self ends after or where the range starts.
if min <= max && self.0 <= max && min <= self.1 {
acc.add(Arc::new(IntT(self.0.max(min), self.1.min(max))));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else if let Some(remove) = remove.as_any().downcast_ref::<Self>() {
if remove.0 <= self.0 && self.1 <= remove.1 {
Some(Type::empty())
} else if remove.0 <= self.0 && self.0 <= remove.1 && remove.1 <= self.1 {
if remove.1 + 1 <= self.1 {
Some(Type::new(Self(remove.1 + 1, self.1)))
} else {
Some(Type::empty())
}
} else if self.0 <= remove.0 && remove.0 <= self.1 && self.1 <= remove.1 {
if self.0 <= remove.0 + 1 {
Some(Type::new(Self(self.0, remove.0 - 1)))
} else {
Some(Type::empty())
}
} else if self.0 < remove.0 && remove.0 <= remove.1 && remove.1 < self.1 {
Some(Type::newm(vec![
Arc::new(Self(self.0, remove.0 - 1)),
Arc::new(Self(remove.1 + 1, self.1)),
]))
} else {
None
}
} else {
None
}
};
add_range(INT_MIN, INT32U_MIN.saturating_sub(1));
add_range(INT32U_MIN, INT32S_MIN.saturating_sub(1));
add_range(INT32S_MIN, -129);
add_range(-128, -2);
add_range(-1, -1);
add_range(0, 0);
add_range(1, 1);
add_range(2, 127);
add_range(128, 255);
add_range(256, 65535);
add_range(65536, INT32S_MAX);
add_range(INT32S_MAX.saturating_add(1), INT32U_MAX);
add_range(INT32U_MAX.saturating_add(1), INT_MAX);
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -142,20 +142,10 @@ pub trait MersType: Any + Debug + Send + Sync {
fn is_same_type_as(&self, other: &dyn MersType) -> bool;
/// This doesn't handle the case where target is Type (Type::is_included_in handles it)
fn is_included_in(&self, target: &dyn MersType) -> bool;
/// Returns all types that can result from the use of this type.
/// Usually, this is just `acc.add(Arc::new(self.clone()))`
/// but if there exists one or more inner types, this becomes interesting:
/// Using `(int/string)` will end up being either `(int)` or `(string)`,
/// so this function should add `(int)` and `(string)`.
/// Since `(int/string)` can't exist at runtime, we don't need to list `self`.
/// note also: `subtypes` has to be called recursively, i.e. you would have to call `.substring` on `int` and `string`.
fn subtypes(&self, acc: &mut Type);
/// like `subtypes`, but returns the accumulator
fn subtypes_type(&self) -> Type {
let mut acc = Type::empty();
self.subtypes(&mut acc);
acc
}
/// Returns `self` with `remove` removed, if it is different from `self`.
/// This must, at least, return `Some(Type::empty())` if `self.is_included_in(remove)`.
/// For example, `(Int<1..9>).remove(Int<4..6>)` would return `Some(Int<1..3>/Int<7..9>)`.
fn without(&self, remove: &dyn MersType) -> Option<Type>;
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
@ -189,8 +179,8 @@ impl MersType for TypeWithOnlyName {
fn is_included_in(&self, _target: &dyn MersType) -> bool {
false
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()))
fn without(&self, _remove: &dyn MersType) -> Option<Type> {
None
}
fn as_any(&self) -> &dyn Any {
self
@ -478,6 +468,29 @@ impl Type {
self.add(Arc::clone(t));
}
}
pub fn without_in_place(&mut self, remove: &dyn MersType) {
let mut rm = vec![];
let mut add = vec![];
for (i, t) in self.types.iter_mut().enumerate() {
if t.is_included_in(remove) {
rm.push(i);
} else if let Some(without) = t.without(remove) {
rm.push(i);
add.push(without);
}
}
for i in rm.into_iter().rev() {
self.types.swap_remove(i);
}
for t in add {
self.add_all(&t);
}
}
pub fn without_in_place_all(&mut self, remove: &Self) {
for t in &remove.types {
self.without_in_place(t.as_ref());
}
}
pub fn dereference(&self) -> Option<Self> {
let mut o = Self::empty();
for t in &self.types {
@ -514,17 +527,6 @@ impl Type {
pub fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.types.iter().all(|s| s.is_included_in(target))
}
pub fn subtypes(&self, acc: &mut Type) {
for t in &self.types {
t.subtypes(acc);
}
}
pub fn subtypes_type(&self) -> Type {
let mut acc = Type::empty();
acc.smart_type_simplification = false;
self.subtypes(&mut acc);
acc
}
pub fn iterable(&self) -> Option<Type> {
let mut o = Self::empty();
for t in self.types.iter() {

View File

@ -128,8 +128,62 @@ impl MersType for ObjectT {
})
})
}
fn subtypes(&self, acc: &mut Type) {
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.len()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
let m = self.0.len();
if let Some(remove) = remove
.as_any()
.downcast_ref::<Self>()
.filter(|r| r.0.len() <= m)
{
let mut out = Type::empty();
for i1 in 0usize.. {
let mut self_tuple = Vec::with_capacity(m);
let mut i1 = i1;
for j in 0..m {
let mm = self.0[j].1.types.len();
self_tuple.push((self.0[j].0, &self.0[j].1.types[i1 % mm]));
i1 /= mm;
}
if i1 != 0 {
break;
}
let mut covered = false;
for i2 in 0usize.. {
let mut remove_tuple = Vec::with_capacity(m);
let mut i2 = i2;
for j in 0..remove.0.len() {
let mm = remove.0[j].1.types.len();
remove_tuple.push((remove.0[j].0, &remove.0[j].1.types[i2 % mm]));
i2 /= mm;
}
if i2 != 0 {
break;
}
if (0..m).all(|j| {
remove_tuple
.iter()
.find(|(v, _)| *v == self_tuple[j].0)
.is_none_or(|(_, r)| {
self_tuple[j].1.as_ref().is_included_in(r.as_ref())
})
}) {
covered = true;
break;
}
}
if !covered {
out.add(Arc::new(Self(
self_tuple
.iter()
.map(|(vi, v)| (*vi, Type::newm(vec![Arc::clone(v)])))
.collect(),
)));
}
}
Some(out)
} else {
None
}
}
fn as_any(&self) -> &dyn std::any::Any {
self
@ -150,30 +204,6 @@ impl MersType for ObjectT {
}
}
impl ObjectT {
pub fn gen_subtypes_recursively(
&self,
acc: &mut Type,
types: &mut Vec<(usize, Arc<dyn MersType>)>,
) {
if types.len() >= self.len() {
let nt = Self(
types
.iter()
.map(|(s, v)| (s.clone(), Type::newm(vec![Arc::clone(v)])))
.collect(),
);
acc.add(Arc::new(nt));
} else {
for t in self.0[types.len()].1.subtypes_type().types {
types.push((self.0[types.len()].0.clone(), t));
self.gen_subtypes_recursively(acc, types);
types.pop();
}
}
}
}
pub trait ObjectFieldsMap {
fn get_or_add_field(&self, field: &str) -> usize;
}

View File

@ -155,16 +155,11 @@ impl MersType for ReferenceT {
// &int isn't included in &(int/float), otherwise we could assign a float to it
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
// // we don't call subtypes because (int/string) must stay that so we can assign either
// // NOTE: this might not be right...?
// acc.add(Arc::new(self.clone()));
// FOR NOW (until we can put the compile-time type in ReferenceT), add all these types, too
// TODO: Figure out how to fix
// x := if true 1 else 0.5
// &x.debug // prints &Int instead of &{Int/Float} at runtime :(
for t in self.0.subtypes_type().types {
acc.add(Arc::new(Self(Type::newm(vec![t]))));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {

View File

@ -1,4 +1,4 @@
use std::{any::Any, fmt::Display, sync::Arc};
use std::{any::Any, fmt::Display};
use crate::info::DisplayInfo;
@ -51,8 +51,12 @@ impl MersType for StringT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self

View File

@ -107,8 +107,59 @@ impl MersType for TupleT {
false
}
}
fn subtypes(&self, acc: &mut Type) {
self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.0.len()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
let m = self.0.len();
if let Some(remove) = remove
.as_any()
.downcast_ref::<Self>()
.filter(|r| r.0.len() == m)
{
let mut out = Type::empty();
for i1 in 0usize.. {
let mut self_tuple = Vec::with_capacity(m);
let mut i1 = i1;
for j in 0..m {
let mm = self.0[j].types.len();
self_tuple.push(&self.0[j].types[i1 % mm]);
i1 /= mm;
}
if i1 != 0 {
break;
}
let mut covered = false;
for i2 in 0usize.. {
let mut remove_tuple = Vec::with_capacity(m);
let mut i2 = i2;
for j in 0..m {
let mm = remove.0[j].types.len();
remove_tuple.push(&remove.0[j].types[i2 % mm]);
i2 /= mm;
}
if i2 != 0 {
break;
}
if (0..m).all(|j| {
self_tuple[j]
.as_ref()
.is_included_in(remove_tuple[j].as_ref())
}) {
covered = true;
break;
}
}
if !covered {
out.add(Arc::new(Self(
self_tuple
.iter()
.map(|v| Type::newm(vec![Arc::clone(v)]))
.collect(),
)));
}
}
Some(out)
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self
@ -128,23 +179,3 @@ impl MersType for TupleT {
)))
}
}
impl TupleT {
pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec<Arc<dyn MersType>>) {
if types.len() >= self.0.len() {
let nt = Self(
types
.iter()
.map(|v| Type::newm(vec![Arc::clone(v)]))
.collect(),
);
acc.add(Arc::new(nt));
} else {
for t in self.0[types.len()].subtypes_type().types {
types.push(t);
self.gen_subtypes_recursively(acc, types);
types.pop();
}
}
}
}

View File

@ -114,6 +114,68 @@ pub fn parse(
let mut pos_after_first = src.get_pos();
loop {
src.skip_whitespace();
// check for `arg [types] -> expr` function syntax
if let Some('[') = src.peek_char() {
let reset_no_func_pos = src.get_pos();
let _ = src.next_char();
let mut fixed_type = Vec::new();
loop {
src.skip_whitespace();
if let Ok(ty) = super::types::parse_type(src, srca) {
src.skip_whitespace();
if src.peek_word() == "->" {
src.next_word();
if let Ok(ot) = super::types::parse_type(src, srca) {
fixed_type.push((ty, Some(ot)));
} else {
fixed_type.clear();
break;
}
} else {
fixed_type.push((ty, None));
}
} else {
fixed_type.clear();
break;
}
src.skip_whitespace();
match src.next_char() {
Some(']') => break,
Some(',') => continue,
_ => {
fixed_type.clear();
break;
}
}
}
if fixed_type.is_empty() {
src.set_pos(reset_no_func_pos);
} else {
src.skip_whitespace();
let pos_in_src = src.get_pos();
if src.next_word() != "->" {
src.set_pos(reset_no_func_pos);
} else {
src.skip_whitespace();
let run = match parse(src, srca) {
Ok(Some(v)) => v,
Ok(None) => {
return Err(CheckError::new()
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
.msg_str(format!("EOF after `->`")))
}
Err(e) => return Err(e),
};
first = Box::new(program::parsed::function::Function {
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
arg: first,
run,
fixed_type: Some(fixed_type),
});
break;
}
}
}
match src.peek_word_allow_colon() {
":=" => {
let pos_in_src = src.get_pos();
@ -164,6 +226,7 @@ pub fn parse(
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
arg: first,
run,
fixed_type: None,
});
break;
}

View File

@ -19,6 +19,8 @@ pub fn to_mers_func(
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(Info::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| out(a, i))),
run: Arc::new(move |a, i| run(a, i)),
inner_statements: None,

View File

@ -30,6 +30,8 @@ impl Config {
.add_var("lock_update", data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -95,6 +97,8 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for t in &a.types {
if t.as_any().downcast_ref::<data::string::StringT>().is_none() && t.as_any().downcast_ref::<data::tuple::TupleT>().is_none() && t.iterable().is_none() {
@ -122,6 +126,8 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, _i| {
for t in &a.types {
if t.iterable().is_none() {
@ -158,6 +164,8 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, _i| Ok(Type::new(data::reference::ReferenceT(a.clone()))))),
run: Arc::new(|a, _i| {
Ok(Data::new(data::reference::Reference(Arc::new(RwLock::new(a.clone())))))
@ -170,6 +178,8 @@ impl Config {
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
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| {

View File

@ -34,6 +34,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
Ok(Type::newm(vec![
@ -89,6 +91,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
Ok(Type::newm(vec![
@ -133,6 +137,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -161,6 +167,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -195,6 +203,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.types.iter().all(|a| a.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) {
Ok(data::bool::bool_type())
@ -224,6 +234,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) {
Ok(data::bool::bool_type())
@ -253,6 +265,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -282,6 +296,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -311,6 +327,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -340,6 +358,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
@ -431,8 +451,12 @@ impl MersType for ChildProcessT {
fn is_included_in(&self, target: &dyn MersType) -> bool {
target.as_any().is::<Self>()
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn std::any::Any {
self

View File

@ -15,6 +15,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let mut out = Type::empty();
for a in a.types.iter() {

View File

@ -144,6 +144,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for a in &a.types {
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -229,6 +231,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let data = if let Some(a) = a.iterable() {
a
@ -246,6 +250,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let data = if let Some(a) = a.iterable() {
a
@ -301,6 +307,8 @@ fn genfunc_iter_and_func(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| iter_out_arg(a, i, name, |f| ft(f)))),
run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
@ -359,6 +367,8 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| {
iter_out_arg(a, i, name, |f: &T| ft(f), type_sample)
})),
@ -607,13 +617,16 @@ impl MersType for IterT {
false
}
}
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn iterable(&self) -> Option<Type> {
Some(self.2.clone())
}
fn subtypes(&self, acc: &mut Type) {
// NOTE: This might not be good enough
acc.add(Arc::new(self.clone()));
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@ -655,6 +668,8 @@ fn genfunc_iter_in_val_out(
Function {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| {
if let Some(iter_over) = a.iterable() {
if iter_over.is_included_in(&iter_type) {
@ -748,8 +763,12 @@ impl MersType for RangeT {
self.is_empty() || (!target.is_empty() && self.0 >= target.0 && self.1 <= target.1)
})
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(Clone::clone(self)))
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn std::any::Any {
self

View File

@ -37,6 +37,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if let Some(a) = a.dereference() {
let mut out = Type::empty();
@ -85,6 +87,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -148,6 +152,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -221,6 +227,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let mut o = Type::empty();
for t in a.types.iter() {
@ -298,6 +306,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let mut o = Type::empty();
for t in a.types.iter() {
@ -369,6 +379,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
if let Some(v) = a.iterable() {
Ok(Type::new(ListT(v)))
@ -464,12 +476,11 @@ impl MersType for ListT {
.downcast_ref::<Self>()
.is_some_and(|v| self.0.is_included_in(&v.0))
}
fn subtypes(&self, acc: &mut Type) {
// The type of an empty list is a list where the items are `<unreachable>`
acc.add(Arc::new(Self(Type::empty())));
// All possible list types
for t in self.0.subtypes_type().types {
acc.add(Arc::new(Self(Type::newm(vec![t]))));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@ -33,6 +33,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, _i| {
let mut out = Type::empty();
for t in a.types.iter() {
@ -59,6 +61,8 @@ impl Config {
.add_var("thread_finished", data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
for t in a.types.iter() {
if !t.as_any().is::<ThreadT>() {
@ -80,6 +84,8 @@ impl Config {
.add_var("thread_await", data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, i| {
let mut out = Type::empty();
for t in a.types.iter() {
@ -162,9 +168,11 @@ impl MersType for ThreadT {
false
}
}
fn subtypes(&self, acc: &mut Type) {
for t in self.0.subtypes_type().types {
acc.add(Arc::new(Self(Type::newm(vec![t]))));
fn without(&self, remove: &dyn MersType) -> Option<Type> {
if self.is_included_in(remove) {
Some(Type::empty())
} else {
None
}
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@ -91,6 +91,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
run: Arc::new(|a, i| {
let a2 = a.get();
@ -114,6 +116,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| {
if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() {
@ -133,6 +137,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| {
if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() {
@ -151,6 +157,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| {
if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() {
@ -170,6 +178,8 @@ impl Config {
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| {
if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() {

View File

@ -3,6 +3,7 @@ use std::sync::{Arc, Mutex};
use crate::{
data,
errors::{CheckError, SourceRange},
parsing::types::ParsedType,
program::{self, run::CheckInfo},
};
@ -13,6 +14,7 @@ pub struct Function {
pub pos_in_src: SourceRange,
pub arg: Box<dyn MersStatement>,
pub run: Box<dyn MersStatement>,
pub fixed_type: Option<Vec<(Vec<ParsedType>, Option<Vec<ParsedType>>)>>,
}
impl MersStatement for Function {
@ -38,6 +40,8 @@ impl MersStatement for Function {
func_no_info: data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
fixed_type: self.fixed_type.clone(),
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |a, i| {
arg2.check(i, Some(a))?;
Ok(run2.check(i, None)?)

View File

@ -56,6 +56,8 @@ impl MersStatement for IncludeMers {
func_no_info: data::function::Function {
info: info::Info::neverused(),
info_check: Arc::new(Mutex::new(info::Info::neverused())),
fixed_type: None,
fixed_type_out: Arc::new(Mutex::new(None)),
out: Ok(Arc::new(move |_, i| {
compiled.check(&mut i.duplicate(), None)
})),

View File

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use crate::{
data::{self, Data, Type},
@ -25,7 +25,7 @@ impl MersStatement for Try {
return Err("can't init to statement type Try".to_string().into());
}
let mut t = Type::empty();
let arg = self.arg.check(info, init_to)?;
let mut arg = self.arg.check(info, init_to)?;
let funcs = self
.funcs
.iter()
@ -46,19 +46,34 @@ impl MersStatement for Try {
};
drop(unused_try_statements_lock);
drop(index_lock);
for arg in arg.subtypes_type().types.iter() {
let mut found = false;
let mut errs = vec![];
for (i, func) in funcs.iter().enumerate() {
let mut func_res = Type::empty();
let mut func_err = None;
'func_options: for (i, func) in funcs.iter().enumerate() {
// TODO! handle the case where a function is a one-of-multiple type...
if func.types.len() != 1 {
return Err(format!(
"Try-statement requires clearly defined functions, but got type {}",
func.with_info(info)
)
.into());
}
for ft in func.types.iter() {
if let Some(ft) = ft.executable() {
match ft.o(&Type::newm(vec![Arc::clone(arg)])) {
let using_func = |t: &mut Type, func_res: &Type| {
// found the function to use
info.global.unused_try_statements.lock().unwrap()[my_index].1[i] = None;
t.add_all(func_res);
};
match ft.o_try(&arg) {
Ok(res) => {
func_res.add_all(&res);
using_func(&mut t, &res);
arg = Type::empty();
break 'func_options;
}
Err((_, covered)) => {
for (t_in, t_out) in &covered {
arg.without_in_place_all(t_in);
using_func(&mut t, t_out);
}
}
Err(e) => func_err = Some(e),
}
} else {
return Err(CheckError::new()
@ -74,35 +89,33 @@ impl MersStatement for Try {
]));
}
}
if let Some(err) = func_err {
// can't use this function for this argument
errs.push(err);
} else {
// found the function to use
info.global.unused_try_statements.lock().unwrap()[my_index].1[i] = None;
found = true;
t.add_all(&func_res);
break;
}
}
if !found {
if !arg.types.is_empty() {
let mut err = CheckError::new()
.msg_str(format!(
"try: no function found for argument of type {}.",
"try: uncovered argument type {}.",
arg.simplified_as_string(info)
))
.src(vec![(
self.pos_in_src.clone(),
Some(EColor::TryNoFunctionFound),
)]);
for (i, e) in errs.into_iter().enumerate() {
err = err
.msg_str(format!("Error for function #{}:", i + 1))
.err(e);
for (i, func) in funcs.iter().enumerate() {
err = err.msg_str(format!(
"Error for function #{} {}:",
i + 1,
func.with_info(info)
));
for e in func
.types
.iter()
.filter_map(|t| t.executable().unwrap().o(&arg).err())
{
err = err.err(e);
}
}
return Err(err);
}
}
Ok(t)
}
fn run_custom(&self, info: &mut Info) -> Result<Data, CheckError> {