remove diff, add subtract to replace it and work with iters, add lt, gt, ltoe, gtoe for < > <= >=

This commit is contained in:
Mark 2023-11-07 18:37:37 +01:00
parent 79660c1976
commit db59a1e92e
12 changed files with 161 additions and 21 deletions

0
examples/00_Hello_World.mers Normal file → Executable file
View File

0
examples/01_Hello_Name.mers Normal file → Executable file
View File

0
examples/02_Calc_Sum.mers Normal file → Executable file
View File

0
examples/03_Basic_Calculator.mers Normal file → Executable file
View File

0
examples/04_Greatest_Common_Divisor.mers Normal file → Executable file
View File

0
examples/05_Matrix_Multiplicator.mers Normal file → Executable file
View File

0
examples/fib.mers Normal file → Executable file
View File

0
examples/iter.mers Normal file → Executable file
View File

0
examples/try.mers Normal file → Executable file
View File

View File

@ -329,6 +329,9 @@ impl MersType for Type {
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.types.iter().all(|t| t.is_included_in_single(target))
}
fn is_included_in(&self, target: &dyn MersType) -> bool {
self.types.iter().all(|t| t.is_included_in(target))
}
fn subtypes(&self, acc: &mut Type) {
for t in &self.types {
t.subtypes(acc);

View File

@ -12,11 +12,15 @@ use super::Config;
impl Config {
/// `sum: fn` returns the sum of all the numbers in the tuple
/// `diff: fn` returns b - a
/// `minus: fn` returns the first number minus all the others
/// `product: fn` returns the product of all the numbers in the tuple
/// `div: fn` returns a / b. Performs integer division if a and b are both integers.
/// `modulo: fn` returns a % b
/// `signum: fn` returns 1 for positive numbers, -1 for negative ones and 0 for 0 (always returns an Int, even when input is Float)
/// `lt: fn` returns true if the input keeps increasing, that is, for (a, b), a < b, for (a, b, c), a < b < c, and so on.
/// `gt: fn` returns true if the input keeps decreasing, that is, for (a, b), a > b, for (a, b, c), a > b > c, and so on.
/// `ltoe: fn` returns true if the input only increases, that is, for (a, b), a <= b, for (a, b, c), a <= b <= c, and so on.
/// `gtoe: fn` returns true if the input only decreases, that is, for (a, b), a >= b, for (a, b, c), a >= b >= c, and so on.
/// `parse_int: fn` parses a string to an int, returns () on failure
/// `parse_float: fn` parses a string to an int, returns () on failure
/// TODO!
@ -25,7 +29,36 @@ impl Config {
/// `ceil: fn` rounds the float [?] and returns an int
/// `floor: fn` rounds the float [?] and returns an int
pub fn with_math(self) -> Self {
self.add_var("parse_float".to_string(), Data::new(data::function::Function {
self
.add_var("lt".to_string(), Data::new(ltgtoe_function("lt".to_string(), |l, r| match (l, r) {
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l < r,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) < r,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l < r as f64,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l < r,
})))
.add_var("gt".to_string(), Data::new(ltgtoe_function("gt".to_string(), |l, r| match (l, r) {
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l > r,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) > r,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l > r as f64,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l > r,
})))
.add_var("ltoe".to_string(), Data::new(ltgtoe_function("ltoe".to_string(), |l, r| match (l, r) {
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l <= r,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) <= r,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l <= r as f64,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l <= r,
})))
.add_var("gtoe".to_string(), Data::new(ltgtoe_function("gtoe".to_string(), |l, r| match (l, r) {
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l >= r,
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) >= r,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l >= r as f64,
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l >= r,
})))
.add_var("parse_float".to_string(), Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
@ -125,25 +158,6 @@ impl Config {
}
} else { unreachable!() }),
}))
.add_var("diff".to_string(), Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| two_tuple_to_num(a, "diff")),
run: Arc::new(|a, _i| if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
let left = t.0[0].get();
let right = t.0[1].get();
let (left, right) = (left.as_any(), right.as_any());
match (left.downcast_ref::<data::int::Int>(), left.downcast_ref::<data::float::Float>(),
right.downcast_ref::<data::int::Int>(), right.downcast_ref::<data::float::Float>()
) {
(Some(data::int::Int(l)), None, Some(data::int::Int(r)), None) => Data::new(data::int::Int(r - l)),
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => Data::new(data::float::Float(r - *l as f64)),
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => Data::new(data::float::Float(*r as f64 - l)),
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => Data::new(data::float::Float(r - l)),
_ => unreachable!(),
}
} else { unreachable!() }),
}))
.add_var(
"sum".to_string(),
Data::new(data::function::Function {
@ -204,6 +218,79 @@ impl Config {
}
}),
}),
)
.add_var(
"subtract".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
let mut ints = false;
let mut floats = false;
for a in &a.types {
if let Some(i) = a.iterable() {
if i.types
.iter()
.all(|t| t.as_any().downcast_ref::<data::int::IntT>().is_some())
{
ints = true;
} else if i.types.iter().all(|t| {
t.as_any().downcast_ref::<data::int::IntT>().is_some()
|| t.as_any().downcast_ref::<data::float::FloatT>().is_some()
}) {
floats = true;
} else {
return Err(format!("cannot subtract on iterator over type {i} because it contains types that aren't int/float").into())
}
} else {
return Err(format!(
"cannot subtract over non-iterable type {a}"
).into());
}
}
Ok(match (ints, floats) {
(_, true) => Type::new(data::float::FloatT),
(true, false) => Type::new(data::int::IntT),
(false, false) => Type::empty(),
})
}),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
let mut first = true;
let mut sumi = 0;
let mut sumf = 0.0;
let mut usef = false;
for val in i {
if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
if first {
sumi = i.0;
} else {
sumi -= i.0;
}
} else if let Some(i) =
val.get().as_any().downcast_ref::<data::float::Float>()
{
if first {
sumf = i.0;
} else {
sumf -= i.0;
}
usef = true;
}
if first {
first = false;
}
}
if usef {
Data::new(data::float::Float(sumi as f64 + sumf))
} else {
Data::new(data::int::Int(sumi))
}
} else {
unreachable!("sum called on non-tuple")
}
}),
}),
)
.add_var(
"product".to_string(),
@ -301,3 +388,53 @@ fn two_tuple_to_num(a: &Type, func_name: &str) -> Result<Type, CheckError> {
Type::new(data::int::IntT)
})
}
fn ltgtoe_function(
func_name: String,
op: impl Fn(IntOrFloatOrNothing, IntOrFloatOrNothing) -> bool + Send + Sync + 'static,
) -> data::function::Function {
data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, _i| {
if let Some(iter_type) = a.iterable() {
let iter_required_type = Type::newm(vec![
Arc::new(data::int::IntT),
Arc::new(data::float::FloatT),
]);
if iter_type.is_included_in(&iter_required_type) {
Ok(Type::new(data::bool::BoolT))
} else {
Err(CheckError::from(format!("Cannot use {func_name} on iterator over type {iter_type} (has to be at most {iter_required_type}).")))
}
} else {
Err(CheckError::from(format!("Cannot use {func_name}")))
}
}),
run: Arc::new(move |a, _i| {
let mut prev = IntOrFloatOrNothing::Nothing;
for item in a.get().iterable().unwrap() {
let item = item.get();
let new = if let Some(data::int::Int(v)) = item.as_any().downcast_ref() {
IntOrFloatOrNothing::Int(*v)
} else if let Some(data::float::Float(v)) = item.as_any().downcast_ref() {
IntOrFloatOrNothing::Float(*v)
} else {
unreachable!()
};
if op(prev, new) {
prev = new;
} else {
return Data::new(data::bool::Bool(false));
}
}
Data::new(data::bool::Bool(true))
}),
}
}
#[derive(Clone, Copy)]
enum IntOrFloatOrNothing {
Nothing,
Int(isize),
Float(f64),
}

0
mers_lib/src/program/configs/with_string.rs Normal file → Executable file
View File