mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 05:43:53 +01:00
convert more stdlib functions and add rounding
converted with_base and with_math
This commit is contained in:
parent
50928cca1d
commit
08a82733e9
@ -1,61 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use mers_lib::{
|
|
||||||
data::{self, Data, Type},
|
|
||||||
errors::CheckError,
|
|
||||||
prelude_compile::{parse, Config, Source},
|
|
||||||
program::parsed::CompInfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
eprintln!("This is valid:");
|
|
||||||
run("my_custom_var.debug.rust_func.debug".to_owned()).unwrap();
|
|
||||||
eprintln!();
|
|
||||||
|
|
||||||
eprintln!("This is not:");
|
|
||||||
let e = run("5.rust_func".to_owned()).err().unwrap();
|
|
||||||
eprintln!("{e:?}");
|
|
||||||
}
|
|
||||||
fn run(src: String) -> Result<(), CheckError> {
|
|
||||||
let mut source = Source::new_from_string(src);
|
|
||||||
let srca = Arc::new(source.clone());
|
|
||||||
let parsed = parse(&mut source, &srca)?;
|
|
||||||
|
|
||||||
// Add our custom variables to the `Config`
|
|
||||||
let (mut i1, mut i2, mut i3) = Config::new()
|
|
||||||
.bundle_std()
|
|
||||||
.add_var(
|
|
||||||
"my_custom_var".to_owned(),
|
|
||||||
Data::new(data::string::String(format!("my custom value!"))),
|
|
||||||
)
|
|
||||||
.add_var(
|
|
||||||
"rust_func".to_owned(),
|
|
||||||
Data::new(data::function::Function::new_generic(
|
|
||||||
|arg| {
|
|
||||||
// If the input is a string, the output is a string.
|
|
||||||
// Otherwise, the function is used incorrectly.
|
|
||||||
if arg.is_included_in_single(&data::string::StringT) {
|
|
||||||
Ok(Type::new(data::string::StringT))
|
|
||||||
} else {
|
|
||||||
// Wrong argument type. The code won't compile and this is the error message shown to the user.
|
|
||||||
Err(format!("Can't call rust_func with non-string argument {arg}!").into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|arg| {
|
|
||||||
let arg = arg.get();
|
|
||||||
let arg = &arg
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<data::string::String>()
|
|
||||||
.unwrap()
|
|
||||||
.0;
|
|
||||||
Ok(Data::new(data::string::String(arg.chars().rev().collect())))
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
.infos();
|
|
||||||
|
|
||||||
let compiled = parsed.compile(&mut i1, CompInfo::default())?;
|
|
||||||
compiled.check(&mut i3, None)?;
|
|
||||||
compiled.run(&mut i2)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -40,25 +40,25 @@ impl Clone for Function {
|
|||||||
impl Function {
|
impl Function {
|
||||||
pub fn new_static(
|
pub fn new_static(
|
||||||
out: Vec<(Type, Type)>,
|
out: Vec<(Type, Type)>,
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
run: impl Fn(Data, &mut Info) -> Result<Data, CheckError> + Send + Sync + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
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: Err(Arc::new(out)),
|
out: Err(Arc::new(out)),
|
||||||
run: Arc::new(move |a, _| run(a)),
|
run: Arc::new(run),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new_generic(
|
pub fn new_generic(
|
||||||
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
|
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
run: impl Fn(Data, &mut Info) -> Result<Data, CheckError> + Send + Sync + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
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, _| out(a))),
|
out: Ok(Arc::new(move |a, _| out(a))),
|
||||||
run: Arc::new(move |a, _| run(a)),
|
run: Arc::new(run),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::sync::Arc;
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, Type},
|
data::{self, Data, MersData, Type},
|
||||||
@ -7,8 +7,23 @@ use crate::{
|
|||||||
|
|
||||||
use super::{FromMersData, ToMersData};
|
use super::{FromMersData, ToMersData};
|
||||||
|
|
||||||
|
pub fn fun<I: FromMersData + 'static, O: ToMersData + 'static>(
|
||||||
|
f: fn(I, &mut crate::program::run::Info) -> Result<O, CheckError>,
|
||||||
|
) -> impl StaticMersFunc {
|
||||||
|
Box::new(f)
|
||||||
|
}
|
||||||
pub fn func<I: FromMersData + 'static, O: ToMersData + 'static>(
|
pub fn func<I: FromMersData + 'static, O: ToMersData + 'static>(
|
||||||
f: fn(I) -> Result<O, CheckError>,
|
f: fn(I, &mut crate::program::run::Info) -> Result<O, CheckError>,
|
||||||
|
) -> data::function::Function {
|
||||||
|
Box::new(f).mers_func()
|
||||||
|
}
|
||||||
|
pub fn func_end<I: FromMersData + 'static>(
|
||||||
|
f: fn(I, &mut crate::program::run::Info) -> !,
|
||||||
|
) -> data::function::Function {
|
||||||
|
Box::new(f).mers_func()
|
||||||
|
}
|
||||||
|
pub fn func_err<I: FromMersData + 'static>(
|
||||||
|
f: fn(I, &mut crate::program::run::Info) -> CheckError,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
Box::new(f).mers_func()
|
Box::new(f).mers_func()
|
||||||
}
|
}
|
||||||
@ -31,10 +46,14 @@ pub fn func<I: FromMersData + 'static, O: ToMersData + 'static>(
|
|||||||
|
|
||||||
pub trait StaticMersFunc: Sized + 'static + Send + Sync {
|
pub trait StaticMersFunc: Sized + 'static + Send + Sync {
|
||||||
fn types() -> Vec<(Type, Type)>;
|
fn types() -> Vec<(Type, Type)>;
|
||||||
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>>;
|
fn run(
|
||||||
|
&self,
|
||||||
|
a: &(impl MersData + ?Sized),
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Option<Result<Data, CheckError>>;
|
||||||
fn mers_func(self) -> data::function::Function {
|
fn mers_func(self) -> data::function::Function {
|
||||||
data::function::Function::new_static(Self::types(), move |a| {
|
data::function::Function::new_static(Self::types(), move |a, i| {
|
||||||
match self.run(a.get().as_ref()) {
|
match self.run(a.get().as_ref(), i) {
|
||||||
Some(Ok(v)) => Ok(v),
|
Some(Ok(v)) => Ok(v),
|
||||||
Some(Err(e)) => Err(e),
|
Some(Err(e)) => Err(e),
|
||||||
None => Err(CheckError::from(format!(
|
None => Err(CheckError::from(format!(
|
||||||
@ -52,13 +71,55 @@ pub struct TwoFuncs<A: StaticMersFunc, B: StaticMersFunc>(pub A, pub B);
|
|||||||
pub trait Func: Send + Sync + 'static {
|
pub trait Func: Send + Sync + 'static {
|
||||||
type I: FromMersData;
|
type I: FromMersData;
|
||||||
type O: ToMersData;
|
type O: ToMersData;
|
||||||
fn run_func(&self, i: Self::I) -> Result<Self::O, CheckError>;
|
fn run_func(
|
||||||
|
&self,
|
||||||
|
i: Self::I,
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Result<Self::O, CheckError>;
|
||||||
}
|
}
|
||||||
impl<I: FromMersData + 'static, O: ToMersData + 'static> Func for fn(I) -> Result<O, CheckError> {
|
impl<I: FromMersData + 'static, O: ToMersData + 'static> Func
|
||||||
|
for fn(I, &mut crate::program::run::Info) -> Result<O, CheckError>
|
||||||
|
{
|
||||||
type I = I;
|
type I = I;
|
||||||
type O = O;
|
type O = O;
|
||||||
fn run_func(&self, i: Self::I) -> Result<Self::O, CheckError> {
|
fn run_func(
|
||||||
self(i)
|
&self,
|
||||||
|
i: Self::I,
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Result<Self::O, CheckError> {
|
||||||
|
self(i, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UnreachableDontConstruct(PhantomData<Self>);
|
||||||
|
impl ToMersData for UnreachableDontConstruct {
|
||||||
|
fn as_type_to() -> Type {
|
||||||
|
Type::empty()
|
||||||
|
}
|
||||||
|
fn represent(self) -> Data {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: FromMersData + 'static> Func for fn(I, &mut crate::program::run::Info) -> ! {
|
||||||
|
type I = I;
|
||||||
|
type O = UnreachableDontConstruct;
|
||||||
|
fn run_func(
|
||||||
|
&self,
|
||||||
|
i: Self::I,
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Result<Self::O, CheckError> {
|
||||||
|
self(i, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: FromMersData + 'static> Func for fn(I, &mut crate::program::run::Info) -> CheckError {
|
||||||
|
type I = I;
|
||||||
|
type O = UnreachableDontConstruct;
|
||||||
|
fn run_func(
|
||||||
|
&self,
|
||||||
|
i: Self::I,
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Result<Self::O, CheckError> {
|
||||||
|
Err(self(i, info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,8 +127,14 @@ impl<F: Func + ?Sized> StaticMersFunc for Box<F> {
|
|||||||
fn types() -> Vec<(Type, Type)> {
|
fn types() -> Vec<(Type, Type)> {
|
||||||
vec![(F::I::as_type_from(), F::O::as_type_to())]
|
vec![(F::I::as_type_from(), F::O::as_type_to())]
|
||||||
}
|
}
|
||||||
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>> {
|
fn run(
|
||||||
F::I::try_represent(a, |v| v.map(|v| self.run_func(v).map(|v| v.represent())))
|
&self,
|
||||||
|
a: &(impl MersData + ?Sized),
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Option<Result<Data, CheckError>> {
|
||||||
|
F::I::try_represent(a, |v| {
|
||||||
|
v.map(|v| self.run_func(v, info).map(|v| v.represent()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +151,11 @@ impl<A: StaticMersFunc, B: StaticMersFunc> StaticMersFunc for TwoFuncs<A, B> {
|
|||||||
}
|
}
|
||||||
o
|
o
|
||||||
}
|
}
|
||||||
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>> {
|
fn run(
|
||||||
self.0.run(a).or_else(|| self.1.run(a))
|
&self,
|
||||||
|
a: &(impl MersData + ?Sized),
|
||||||
|
info: &mut crate::program::run::Info,
|
||||||
|
) -> Option<Result<Data, CheckError>> {
|
||||||
|
self.0.run(a, info).or_else(|| self.1.run(a, info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ pub fn to_mers_func_with_in_out_types(
|
|||||||
out_type: Type,
|
out_type: Type,
|
||||||
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
|
||||||
) -> data::function::Function {
|
) -> data::function::Function {
|
||||||
data::function::Function::new_static(vec![(in_type, out_type)], run)
|
data::function::Function::new_static(vec![(in_type, out_type)], move |a, _| run(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_mers_func_concrete_string_to_any(
|
pub fn to_mers_func_concrete_string_to_any(
|
||||||
|
@ -9,23 +9,24 @@ use crate::{
|
|||||||
program::run::{CheckInfo, Info},
|
program::run::{CheckInfo, Info},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::{
|
||||||
|
gen::{
|
||||||
|
function::{func, func_end, func_err},
|
||||||
|
OneOf,
|
||||||
|
},
|
||||||
|
Config,
|
||||||
|
};
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// `deref: fn` clones the value from a reference
|
/// `deref: fn` clones the value from a reference
|
||||||
/// `mkref: fn` returns a reference to a copy of the value
|
/// `mkref: fn` returns a reference to a copy of the value
|
||||||
/// `eq: fn` returns true if all the values are equal, otherwise false.
|
/// `eq: fn` returns true if all the values are equal, otherwise false.
|
||||||
/// `loop: fn` runs a function until it returns (T) instead of (), then returns T. Also works with ((), f) instead of f for ().loop(() -> { ... }) syntax, which may be more readable
|
|
||||||
/// `try: fn` runs the first valid function with the argument. usage: (arg, (f1, f2, f3)).try
|
|
||||||
/// NOTE: try's return type may miss some types that can actually happen when using it on tuples, so... don't do ((a, b), (f1, any -> ())).try unless f1 also returns ()
|
|
||||||
/// `len: fn` gets the length of strings or tuples
|
/// `len: fn` gets the length of strings or tuples
|
||||||
/// `sleep: fn` sleeps for n seconds (pauses the current thread)
|
/// `sleep: fn` sleeps for n seconds (pauses the current thread)
|
||||||
/// `panic: fn` exits the program with the given exit code
|
/// `panic: fn` exits the program with the given exit code
|
||||||
/// `lock_update: fn` locks the value of a reference so you can exclusively modify it: &var.lock_update(v -> (v, 1).sum)
|
/// `lock_update: fn` locks the value of a reference so you can exclusively modify it: &var.lock_update(v -> (v, 1).sum)
|
||||||
pub fn with_base(self) -> Self {
|
pub fn with_base(self) -> Self {
|
||||||
self
|
self
|
||||||
// .add_var("try".to_string(), get_try(false))
|
|
||||||
// .add_var("try_allow_unused".to_string(), get_try(true))
|
|
||||||
.add_var("lock_update".to_string(), Data::new(data::function::Function {
|
.add_var("lock_update".to_string(), Data::new(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())),
|
||||||
@ -74,68 +75,24 @@ impl Config {
|
|||||||
}),
|
}),
|
||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
}))
|
}))
|
||||||
.add_var("sleep".to_string(), Data::new(data::function::Function {
|
.add_var("sleep".to_owned(), Data::new(func(|dur: OneOf<isize, f64>, i| {
|
||||||
info: Info::neverused(),
|
let mut sleep_dur = match dur {
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
OneOf::A(dur) => Duration::from_secs(dur.max(0).try_into().unwrap_or(u64::MAX)),
|
||||||
out: Ok(Arc::new(|a, _i| if a.is_included_in(&Type::newm(vec![
|
OneOf::B(dur) => Duration::from_secs_f64(dur.max(0.0)),
|
||||||
Arc::new(data::int::IntT),
|
};
|
||||||
Arc::new(data::float::FloatT),
|
// limit how long sleep can take
|
||||||
])) {
|
if let Some(cutoff) = i.global.limit_runtime {
|
||||||
Ok(Type::empty_tuple())
|
sleep_dur = sleep_dur.min(cutoff.saturating_duration_since(Instant::now()));
|
||||||
} else {
|
}
|
||||||
Err(format!("cannot call sleep with non-int or non-float argument.").into())
|
std::thread::sleep(sleep_dur);
|
||||||
})),
|
Ok(())
|
||||||
run: Arc::new(|a, i| {
|
})))
|
||||||
let a = a.get();
|
.add_var("exit".to_string(), Data::new(func_end(|code: isize, _| {
|
||||||
let mut sleep_dur = if let Some(data::int::Int(n)) = a.as_any().downcast_ref() {
|
std::process::exit(code.try_into().unwrap_or(255));
|
||||||
Duration::from_secs(*n as _)
|
})))
|
||||||
} else if let Some(data::float::Float(n)) = a.as_any().downcast_ref() {
|
.add_var("panic".to_string(), Data::new(func_err(|message: &str, _| {
|
||||||
Duration::from_secs_f64(*n)
|
CheckError::from(message)
|
||||||
} else {
|
})))
|
||||||
return Err("sleep called on non-int/non-float".into());
|
|
||||||
};
|
|
||||||
// limit how long sleep can take
|
|
||||||
if let Some(cutoff) = i.global.limit_runtime {
|
|
||||||
sleep_dur = sleep_dur.min(cutoff.saturating_duration_since(Instant::now()));
|
|
||||||
}
|
|
||||||
std::thread::sleep(sleep_dur);
|
|
||||||
Ok(Data::empty_tuple())
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}))
|
|
||||||
.add_var("exit".to_string(), Data::new(data::function::Function {
|
|
||||||
info: Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(Arc::new(|a, _i| if a.is_included_in_single(&data::int::IntT) {
|
|
||||||
Ok(Type::empty())
|
|
||||||
} else {
|
|
||||||
Err(format!("cannot call exit with non-int argument").into())
|
|
||||||
})),
|
|
||||||
run: Arc::new(|a, _i| {
|
|
||||||
std::process::exit(a.get().as_any().downcast_ref::<data::int::Int>().map(|i| i.0 as _).unwrap_or(1));
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}))
|
|
||||||
.add_var("panic".to_string(), Data::new(data::function::Function {
|
|
||||||
info: Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(Arc::new(|a, _i| if a.is_included_in_single(&data::string::StringT) {
|
|
||||||
Ok(Type::empty())
|
|
||||||
} else {
|
|
||||||
Err(format!("cannot call panic with non-string argument").into())
|
|
||||||
})),
|
|
||||||
run: Arc::new(|a, _i| {
|
|
||||||
Err(
|
|
||||||
a
|
|
||||||
.get()
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<data::string::String>()
|
|
||||||
.map(|i| i.0.to_owned())
|
|
||||||
.unwrap_or_else(String::new).into()
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"len".to_string(),
|
"len".to_string(),
|
||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
@ -155,8 +112,8 @@ impl Config {
|
|||||||
} else if let Some(s) = a.get().as_any().downcast_ref::<data::string::String>() {
|
} else if let Some(s) = a.get().as_any().downcast_ref::<data::string::String>() {
|
||||||
s.0.len() as _
|
s.0.len() as _
|
||||||
} else if let Some(i) = a.get().iterable() {
|
} else if let Some(i) = a.get().iterable() {
|
||||||
// -1 if more elements than isize can represent
|
// -1 if more elements than isize can represent
|
||||||
i.take(isize::MAX as usize + 1).count() as isize
|
i.take(isize::MAX as usize + 1).count().try_into().unwrap_or(-1)
|
||||||
} else {
|
} else {
|
||||||
return Err("called len on {a:?}, which isn't a tuple or a string".into());
|
return Err("called len on {a:?}, which isn't a tuple or a string".into());
|
||||||
})))
|
})))
|
||||||
@ -235,171 +192,3 @@ impl Config {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn get_try(allow_unused_functions: bool) -> Data {
|
|
||||||
// Data::new(data::function::Function {
|
|
||||||
// info: Info::neverused(),
|
|
||||||
// info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
// out: Arc::new(move |a, _i| {
|
|
||||||
// let mut out = Type::empty();
|
|
||||||
// for t in a.types.iter() {
|
|
||||||
// if let Some(outer_tuple) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
|
||||||
// if outer_tuple.0.len() != 2 {
|
|
||||||
// return Err(format!(
|
|
||||||
// "cannot use try with tuple argument where len != 2 (got len {})",
|
|
||||||
// outer_tuple.0.len()
|
|
||||||
// )
|
|
||||||
// .into());
|
|
||||||
// }
|
|
||||||
// let arg_type = &outer_tuple.0[0];
|
|
||||||
// let functions = &outer_tuple.0[1];
|
|
||||||
// let mut used_functions_and_errors = vec![];
|
|
||||||
// for arg_type in arg_type.subtypes_type().types.iter() {
|
|
||||||
// let arg_type = Type::newm(vec![arg_type.clone()]);
|
|
||||||
// // possibilities for the tuple (f1, f2, f3, ..., fn)
|
|
||||||
// for (fti, ft) in functions.types.iter().enumerate() {
|
|
||||||
// if used_functions_and_errors.len() <= fti {
|
|
||||||
// used_functions_and_errors.push(vec![]);
|
|
||||||
// }
|
|
||||||
// let mut tuple_fallible = true;
|
|
||||||
// let mut tuple_possible = false;
|
|
||||||
// if let Some(ft) = ft.as_any().downcast_ref::<data::tuple::TupleT>() {
|
|
||||||
// // f1, f2, f3, ..., fn
|
|
||||||
// let mut func_errors = vec![];
|
|
||||||
// let mut skip_checks = false;
|
|
||||||
// for (fi, ft) in ft.0.iter().enumerate() {
|
|
||||||
// if used_functions_and_errors[fti].len() <= fi {
|
|
||||||
// used_functions_and_errors[fti].push(vec![]);
|
|
||||||
// }
|
|
||||||
// let mut func_fallible = false;
|
|
||||||
// // possibilities for f_
|
|
||||||
// for (fvi, ft) in ft.types.iter().enumerate() {
|
|
||||||
// if let Some(ft) =
|
|
||||||
// ft.as_any().downcast_ref::<data::function::FunctionT>()
|
|
||||||
// {
|
|
||||||
// if used_functions_and_errors[fti][fi].len() <= fvi {
|
|
||||||
// used_functions_and_errors[fti][fi]
|
|
||||||
// .push(Some(vec![]));
|
|
||||||
// }
|
|
||||||
// if !skip_checks {
|
|
||||||
// func_errors.push((
|
|
||||||
// fvi,
|
|
||||||
// match ft.o(&arg_type) {
|
|
||||||
// Err(e) => {
|
|
||||||
// func_fallible = true;
|
|
||||||
// if let Some(errs) =
|
|
||||||
// &mut used_functions_and_errors[fti]
|
|
||||||
// [fi][fvi]
|
|
||||||
// {
|
|
||||||
// errs.push(e.clone());
|
|
||||||
// }
|
|
||||||
// Some(e)
|
|
||||||
// }
|
|
||||||
// Ok(o) => {
|
|
||||||
// used_functions_and_errors[fti][fi]
|
|
||||||
// [fvi] = None;
|
|
||||||
// tuple_possible = true;
|
|
||||||
// for t in o.types {
|
|
||||||
// out.add(t);
|
|
||||||
// }
|
|
||||||
// None
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return Err(format!(
|
|
||||||
// "try: arguments f1-fn must be functions"
|
|
||||||
// )
|
|
||||||
// .into());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // found a function that won't fail for this arg_type!
|
|
||||||
// if !func_fallible {
|
|
||||||
// tuple_fallible = false;
|
|
||||||
// if tuple_possible {
|
|
||||||
// skip_checks = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if tuple_fallible || !tuple_possible {
|
|
||||||
// // if the argument is {arg_type}, there is no infallible function. add a fallback function to handle this case!
|
|
||||||
// let mut e = CheckError::new()
|
|
||||||
// .msg(format!("if the argument is {arg_type}, there is no infallible function."))
|
|
||||||
// .msg(format!("Add a function to handle this case!"));
|
|
||||||
// for (i, err) in func_errors.into_iter() {
|
|
||||||
// if let Some(err) = err {
|
|
||||||
// e = e
|
|
||||||
// .msg(format!("Error for function #{}:", i + 1))
|
|
||||||
// .err(err);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return Err(e);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return Err(format!(
|
|
||||||
// "try: argument must be (arg, (f1, f2, f3, ..., fn))"
|
|
||||||
// )
|
|
||||||
// .into());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // check for unused functions
|
|
||||||
// if !allow_unused_functions {
|
|
||||||
// for (functions_posibility_index, functions_possibility) in
|
|
||||||
// used_functions_and_errors.into_iter().enumerate()
|
|
||||||
// {
|
|
||||||
// for (func_index, func_possibilities) in
|
|
||||||
// functions_possibility.into_iter().enumerate()
|
|
||||||
// {
|
|
||||||
// for (func_possibility_index, errors_if_unused) in
|
|
||||||
// func_possibilities.into_iter().enumerate()
|
|
||||||
// {
|
|
||||||
// if let Some(errs) = errors_if_unused {
|
|
||||||
// let mut e = CheckError::new().msg(format!("try: For the argument {t}:\nFunction #{}{} is never used. (use `try_allow_unused` to avoid this error){}",
|
|
||||||
// func_index + 1,
|
|
||||||
// if functions_posibility_index != 0 || func_possibility_index != 0 {
|
|
||||||
// format!(" (func-tuple possibility {}, function possibility {})", functions_posibility_index + 1, func_possibility_index + 1)
|
|
||||||
// } else {
|
|
||||||
// format!("")
|
|
||||||
// },
|
|
||||||
// if errs.is_empty() { "" } else { " Errors:" }));
|
|
||||||
// for err in errs {
|
|
||||||
// e = e.err(err);
|
|
||||||
// }
|
|
||||||
// return Err(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return Err(format!("cannot use try with non-tuple argument").into());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Ok(out)
|
|
||||||
// }),
|
|
||||||
// run: Arc::new(|a, _i| {
|
|
||||||
// let tuple = a.get();
|
|
||||||
// let tuple = tuple
|
|
||||||
// .as_any()
|
|
||||||
// .downcast_ref::<data::tuple::Tuple>()
|
|
||||||
// .expect("try: not a tuple");
|
|
||||||
// let arg = &tuple.0[0];
|
|
||||||
// let funcs = tuple.0[1].get();
|
|
||||||
// let funcs = funcs.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
|
||||||
// for func in funcs.0.iter() {
|
|
||||||
// let func = func.get();
|
|
||||||
// let func = func
|
|
||||||
// .as_any()
|
|
||||||
// .downcast_ref::<data::function::Function>()
|
|
||||||
// .unwrap();
|
|
||||||
// if func.check(&arg.get().as_type()).is_ok() {
|
|
||||||
// return func.run(arg.clone());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// unreacha ble!("try: no function found")
|
|
||||||
// }),
|
|
||||||
// inner_statements: None,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::{
|
||||||
|
ops::Rem,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, Type},
|
||||||
@ -6,15 +9,23 @@ use crate::{
|
|||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::{
|
||||||
|
gen::{
|
||||||
|
function::{fun, func, StaticMersFunc, TwoFuncs},
|
||||||
|
OneOf, OneOrNone,
|
||||||
|
},
|
||||||
|
Config,
|
||||||
|
};
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// `sum: fn` returns the sum of all the numbers in the tuple
|
/// `add: fn` returns the sum of all the numbers in the tuple
|
||||||
/// `minus: fn` returns the first number minus all the others
|
/// `sub: fn` returns the first number minus all the others
|
||||||
/// `product: fn` returns the product of all the numbers in the tuple
|
/// `mul: 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.
|
/// `div: fn` returns a / b. Performs integer division if a and b are both integers.
|
||||||
|
/// `remainder: fn` returns a % b
|
||||||
|
/// `modulo: fn` returns a % b, where a % b >= 0
|
||||||
|
/// `abs: fn` returns the absolute value of a, abs(a) or |a|, which is a for a >= 0 and -a for a < 0. For a==isize::MIN, returns isize::MAX, which is one less than the theoretical absolute value of isize::MIN
|
||||||
/// `pow: fn` returns a^b or a**b.
|
/// `pow: fn` returns a^b or a**b.
|
||||||
/// `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)
|
/// `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.
|
/// `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.
|
/// `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.
|
||||||
@ -27,199 +38,88 @@ impl Config {
|
|||||||
/// `round: fn` rounds the float and returns an int
|
/// `round: fn` rounds the float and returns an int
|
||||||
/// `ceil: fn` rounds the float [?] and returns an int
|
/// `ceil: fn` rounds the float [?] and returns an int
|
||||||
/// `floor: fn` rounds the float [?] and returns an int
|
/// `floor: fn` rounds the float [?] and returns an int
|
||||||
|
/// `round_as_float: fn` round ties (x.5) away from zero, return the result as a float
|
||||||
|
/// `ceil_as_float: fn` round all numbers towards +infty, return the result as a float
|
||||||
|
/// `floor_as_float: fn` round all numbers towards -infty, return the result as a float
|
||||||
|
/// `truncate_as_float: fn` round all numbers towards 0, return the result as a float
|
||||||
|
/// `round_ties_even_as_float: fn` round ties (x.5) to the nearest even number, return the result as a float
|
||||||
|
/// `round_to_int: fn` round ties (x.5) away from zero, return the result as an Int (saturates at the Int boundaries, hence the to_int instead of as_int)
|
||||||
|
/// `ceil_to_int: fn` round all numbers towards +infty, return the result as an Int (saturates at the Int boundaries, hence the to_int instead of as_int)
|
||||||
|
/// `floor_to_int: fn` round all numbers towards -infty, return the result as an Int (saturates at the Int boundaries, hence the to_int instead of as_int)
|
||||||
|
/// `truncate_to_int: fn` round all numbers towards 0, return the result as an Int (saturates at the Int boundaries, hence the to_int instead of as_int)
|
||||||
|
/// `round_ties_even_to_int: fn` round ties (x.5) to the nearest even number, return the result as an Int (saturates at the Int boundaries, hence the to_int instead of as_int)
|
||||||
pub fn with_math(self) -> Self {
|
pub fn with_math(self) -> Self {
|
||||||
self.add_var(
|
self.add_var(
|
||||||
|
"parse_float".to_owned(),
|
||||||
|
Data::new(func(|n: &str, _| Ok(OneOrNone(n.parse::<f64>().ok())))),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"parse_int".to_owned(),
|
||||||
|
Data::new(func(|n: &str, _| Ok(OneOrNone(n.parse::<isize>().ok())))),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
"lt".to_string(),
|
"lt".to_string(),
|
||||||
Data::new(ltgtoe_function("lt".to_string(), |l, r| match (l, r) {
|
Data::new(func(|v: (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
|
Ok(match v {
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l < r,
|
(OneOf::A(a), OneOf::A(b)) => a < b,
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) < r,
|
(OneOf::A(a), OneOf::B(b)) => (a as f64) < b,
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l < r as f64,
|
(OneOf::B(a), OneOf::A(b)) => a < (b as f64),
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l < r,
|
(OneOf::B(a), OneOf::B(b)) => a < b,
|
||||||
|
})
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"gt".to_string(),
|
"gt".to_string(),
|
||||||
Data::new(ltgtoe_function("gt".to_string(), |l, r| match (l, r) {
|
Data::new(func(|v: (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
|
Ok(match v {
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l > r,
|
(OneOf::A(a), OneOf::A(b)) => a > b,
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) > r,
|
(OneOf::A(a), OneOf::B(b)) => (a as f64) > b,
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l > r as f64,
|
(OneOf::B(a), OneOf::A(b)) => a > (b as f64),
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l > r,
|
(OneOf::B(a), OneOf::B(b)) => a > b,
|
||||||
|
})
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"ltoe".to_string(),
|
"ltoe".to_string(),
|
||||||
Data::new(ltgtoe_function("ltoe".to_string(), |l, r| match (l, r) {
|
Data::new(func(|v: (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
|
Ok(match v {
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l <= r,
|
(OneOf::A(a), OneOf::A(b)) => a <= b,
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) <= r,
|
(OneOf::A(a), OneOf::B(b)) => (a as f64) <= b,
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l <= r as f64,
|
(OneOf::B(a), OneOf::A(b)) => a <= (b as f64),
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l <= r,
|
(OneOf::B(a), OneOf::B(b)) => a <= b,
|
||||||
|
})
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"gtoe".to_string(),
|
"gtoe".to_string(),
|
||||||
Data::new(ltgtoe_function("gtoe".to_string(), |l, r| match (l, r) {
|
Data::new(func(|v: (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
(IntOrFloatOrNothing::Nothing, _) | (_, IntOrFloatOrNothing::Nothing) => true,
|
Ok(match v {
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Int(r)) => l >= r,
|
(OneOf::A(a), OneOf::A(b)) => a >= b,
|
||||||
(IntOrFloatOrNothing::Int(l), IntOrFloatOrNothing::Float(r)) => (l as f64) >= r,
|
(OneOf::A(a), OneOf::B(b)) => (a as f64) >= b,
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Int(r)) => l >= r as f64,
|
(OneOf::B(a), OneOf::A(b)) => a >= (b as f64),
|
||||||
(IntOrFloatOrNothing::Float(l), IntOrFloatOrNothing::Float(r)) => l >= r,
|
(OneOf::B(a), OneOf::B(b)) => a >= b,
|
||||||
|
})
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.add_var(
|
|
||||||
"parse_float".to_string(),
|
|
||||||
Data::new(data::function::Function {
|
|
||||||
info: program::run::Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(Arc::new(|a, _i| {
|
|
||||||
if a.is_included_in(&Type::new(data::string::StringT)) {
|
|
||||||
Ok(Type::newm(vec![
|
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::float::FloatT)])),
|
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
|
||||||
]))
|
|
||||||
} else {
|
|
||||||
Err(format!("parse_float called on non-string type").into())
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
run: Arc::new(|a, _i| {
|
|
||||||
Ok(
|
|
||||||
if let Ok(n) = a
|
|
||||||
.get()
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<data::string::String>()
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.parse()
|
|
||||||
{
|
|
||||||
Data::one_tuple(Data::new(data::float::Float(n)))
|
|
||||||
} else {
|
|
||||||
Data::empty_tuple()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.add_var(
|
|
||||||
"parse_int".to_string(),
|
|
||||||
Data::new(data::function::Function {
|
|
||||||
info: program::run::Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(Arc::new(|a, _i| {
|
|
||||||
if a.is_included_in(&Type::new(data::string::StringT)) {
|
|
||||||
Ok(Type::newm(vec![
|
|
||||||
Arc::new(data::tuple::TupleT(vec![Type::new(data::int::IntT)])),
|
|
||||||
Arc::new(data::tuple::TupleT(vec![])),
|
|
||||||
]))
|
|
||||||
} else {
|
|
||||||
Err(format!("parse_float called on non-string type").into())
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
run: Arc::new(|a, _i| {
|
|
||||||
Ok(
|
|
||||||
if let Ok(n) = a
|
|
||||||
.get()
|
|
||||||
.as_any()
|
|
||||||
.downcast_ref::<data::string::String>()
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.parse()
|
|
||||||
{
|
|
||||||
Data::one_tuple(Data::new(data::int::Int(n)))
|
|
||||||
} else {
|
|
||||||
Data::empty_tuple()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"signum".to_string(),
|
"signum".to_string(),
|
||||||
Data::new(data::function::Function {
|
Data::new(func(|n: OneOf<isize, f64>, _| {
|
||||||
info: program::run::Info::neverused(),
|
Ok(match n {
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
OneOf::A(n) => n.signum(),
|
||||||
out: Ok(Arc::new(|a, _i| {
|
OneOf::B(n) => {
|
||||||
if a.is_included_in(&Type::newm(vec![
|
if n > 0.0 {
|
||||||
Arc::new(data::int::IntT),
|
1
|
||||||
Arc::new(data::float::FloatT),
|
} else if n < 0.0 {
|
||||||
])) {
|
-1
|
||||||
Ok(Type::new(data::int::IntT))
|
|
||||||
} else {
|
|
||||||
Err(format!("signum called on non-number type").into())
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
run: Arc::new(|a, _i| {
|
|
||||||
Ok(Data::new(data::int::Int(
|
|
||||||
if let Some(n) = a.get().as_any().downcast_ref::<data::int::Int>() {
|
|
||||||
n.0.signum()
|
|
||||||
} else if let Some(n) =
|
|
||||||
a.get().as_any().downcast_ref::<data::float::Float>()
|
|
||||||
{
|
|
||||||
if n.0 > 0.0 {
|
|
||||||
1
|
|
||||||
} else if n.0 < 0.0 {
|
|
||||||
-1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err("called signum on non-number type".into());
|
0
|
||||||
},
|
}
|
||||||
)))
|
}
|
||||||
}),
|
})
|
||||||
inner_statements: None,
|
})),
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"div".to_string(),
|
"add".to_string(),
|
||||||
Data::new(two_num_tuple_to_num(
|
|
||||||
"div",
|
|
||||||
|l, r| {
|
|
||||||
l.checked_div(r)
|
|
||||||
.ok_or_else(|| CheckError::from("attempted to divide by zero"))
|
|
||||||
},
|
|
||||||
|l, r| Ok(l as f64 / r),
|
|
||||||
|l, r| Ok(l / r as f64),
|
|
||||||
|l, r| Ok(l / r),
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
.add_var(
|
|
||||||
"pow".to_string(),
|
|
||||||
Data::new(two_num_tuple_to_num(
|
|
||||||
"pow",
|
|
||||||
|l, r| Ok(l.pow(r.try_into().unwrap_or(u32::MAX))),
|
|
||||||
|l, r| Ok((l as f64).powf(r)),
|
|
||||||
|l, r| {
|
|
||||||
Ok(if let Ok(r) = r.try_into() {
|
|
||||||
l.powi(r)
|
|
||||||
} else {
|
|
||||||
l.powf(r as f64)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|l, r| Ok(l.powf(r)),
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
.add_var(
|
|
||||||
"modulo".to_string(),
|
|
||||||
Data::new(two_num_tuple_to_num(
|
|
||||||
"modulo",
|
|
||||||
|l, r| {
|
|
||||||
l.checked_rem(r).ok_or_else(|| {
|
|
||||||
CheckError::from(
|
|
||||||
"called modulo on two integers, and the second one was zero",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|l, r| Ok(l as f64 % r),
|
|
||||||
|l, r| Ok(l % r as f64),
|
|
||||||
|l, r| Ok(l % r),
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
.add_var(
|
|
||||||
"sum".to_string(),
|
|
||||||
Data::new(num_iter_to_num("sum", Ok(0), |a, v| match (a, v) {
|
Data::new(num_iter_to_num("sum", Ok(0), |a, v| match (a, v) {
|
||||||
(Ok(a), Ok(v)) => Ok(a + v),
|
(Ok(a), Ok(v)) => Ok(a + v),
|
||||||
(Ok(a), Err(v)) => Err(a as f64 + v),
|
(Ok(a), Err(v)) => Err(a as f64 + v),
|
||||||
@ -228,17 +128,27 @@ impl Config {
|
|||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"subtract".to_string(),
|
"sub".to_string(),
|
||||||
Data::new(two_num_tuple_to_num(
|
Data::new(
|
||||||
"subtract",
|
TwoFuncs(
|
||||||
|l, r| Ok(l - r),
|
fun(|(n, d): (isize, isize), _| Ok(n.wrapping_sub(d))),
|
||||||
|l, r| Ok(l as f64 - r),
|
fun(|(n, d): (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
|l, r| Ok(l - r as f64),
|
let n = match n {
|
||||||
|l, r| Ok(l - r),
|
OneOf::A(v) => v as f64,
|
||||||
)),
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
let d = match d {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
Ok(n - d)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"product".to_string(),
|
"mul".to_string(),
|
||||||
Data::new(num_iter_to_num("sum", Ok(1), |a, v| match (a, v) {
|
Data::new(num_iter_to_num("sum", Ok(1), |a, v| match (a, v) {
|
||||||
(Ok(a), Ok(v)) => Ok(a * v),
|
(Ok(a), Ok(v)) => Ok(a * v),
|
||||||
(Ok(a), Err(v)) => Err(a as f64 * v),
|
(Ok(a), Err(v)) => Err(a as f64 * v),
|
||||||
@ -246,6 +156,189 @@ impl Config {
|
|||||||
(Err(a), Err(v)) => Err(a * v),
|
(Err(a), Err(v)) => Err(a * v),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
.add_var(
|
||||||
|
"div".to_string(),
|
||||||
|
Data::new(
|
||||||
|
TwoFuncs(
|
||||||
|
fun(|(n, d): (isize, isize), _| {
|
||||||
|
n.checked_div(d)
|
||||||
|
.ok_or_else(|| CheckError::from("attempted to divide by zero"))
|
||||||
|
}),
|
||||||
|
fun(|(n, d): (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
|
let n = match n {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
let d = match d {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
Ok(n / d)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"remainder".to_string(),
|
||||||
|
Data::new(
|
||||||
|
TwoFuncs(
|
||||||
|
fun(|(n, d): (isize, isize), _| {
|
||||||
|
n.checked_rem(d).ok_or_else(|| {
|
||||||
|
CheckError::from(
|
||||||
|
"attempted to calculate remainder with zero, or overflow occured",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
fun(|(n, d): (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
|
let n = match n {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
let d = match d {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
Ok(n.rem(d))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"modulo".to_string(),
|
||||||
|
Data::new(
|
||||||
|
TwoFuncs(
|
||||||
|
fun(|(n, d): (isize, isize), _| {
|
||||||
|
n.checked_rem_euclid(d).ok_or_else(|| {
|
||||||
|
CheckError::from(
|
||||||
|
"attempted to perform modulo with zero, or overflow occured",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
fun(|(n, d): (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
|
let n = match n {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
let d = match d {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
Ok(n.rem_euclid(d))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"abs".to_string(),
|
||||||
|
Data::new(
|
||||||
|
TwoFuncs(
|
||||||
|
fun(|v: isize, _| Ok(v.saturating_abs())),
|
||||||
|
fun(|v: f64, _| Ok(v.abs())),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"pow".to_string(),
|
||||||
|
Data::new(
|
||||||
|
TwoFuncs(
|
||||||
|
fun(|(l, r): (isize, isize), _| Ok(l.pow(r.try_into().unwrap_or(u32::MAX)))),
|
||||||
|
fun(|(l, r): (OneOf<isize, f64>, OneOf<isize, f64>), _| {
|
||||||
|
let l = match l {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
};
|
||||||
|
Ok(match r {
|
||||||
|
OneOf::A(r) => {
|
||||||
|
if let Ok(r) = r.try_into() {
|
||||||
|
l.powi(r)
|
||||||
|
} else {
|
||||||
|
l.powf(r as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OneOf::B(r) => l.powf(r),
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mers_func(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"as_float".to_owned(),
|
||||||
|
Data::new(func(|v: OneOf<isize, f64>, _| {
|
||||||
|
Ok(match v {
|
||||||
|
OneOf::A(v) => v as f64,
|
||||||
|
OneOf::B(v) => v,
|
||||||
|
})
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"round_as_float".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<f64, _> { Ok(v.round()) })),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"ceil_as_float".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<f64, _> { Ok(v.ceil()) })),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"floor_as_float".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<f64, _> { Ok(v.floor()) })),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"truncate_as_float".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<f64, _> { Ok(v.trunc()) })),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"round_ties_even_as_float".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<f64, _> {
|
||||||
|
Ok(v.round_ties_even())
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"round_to_int".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<isize, _> {
|
||||||
|
Ok(isize_from(v.round()))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"ceil_to_int".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<isize, _> {
|
||||||
|
Ok(isize_from(v.ceil()))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"floor_to_int".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<isize, _> {
|
||||||
|
Ok(isize_from(v.floor()))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"truncate_to_int".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<isize, _> {
|
||||||
|
Ok(isize_from(v.trunc()))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.add_var(
|
||||||
|
"round_ties_even_to_int".to_owned(),
|
||||||
|
Data::new(func(|v: f64, _| -> Result<isize, _> {
|
||||||
|
Ok(isize_from(v.round_ties_even()))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ISIZE_MAX_F: f64 = isize::MAX as _;
|
||||||
|
const ISIZE_MIN_F: f64 = isize::MIN as _;
|
||||||
|
fn isize_from(v: f64) -> isize {
|
||||||
|
if v >= ISIZE_MAX_F {
|
||||||
|
isize::MAX
|
||||||
|
} else if v <= ISIZE_MIN_F {
|
||||||
|
isize::MIN
|
||||||
|
} else {
|
||||||
|
v as isize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,150 +400,3 @@ fn num_iter_to_num(
|
|||||||
inner_statements: None,
|
inner_statements: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (int, int) -> int
|
|
||||||
/// (int, float) -> float
|
|
||||||
/// (float, int) -> float
|
|
||||||
/// (float, float) -> float
|
|
||||||
fn two_num_tuple_to_num(
|
|
||||||
func_name: &'static str,
|
|
||||||
func_ii: impl Fn(isize, isize) -> Result<isize, CheckError> + Send + Sync + 'static,
|
|
||||||
func_if: impl Fn(isize, f64) -> Result<f64, CheckError> + Send + Sync + 'static,
|
|
||||||
func_fi: impl Fn(f64, isize) -> Result<f64, CheckError> + Send + Sync + 'static,
|
|
||||||
func_ff: impl Fn(f64, f64) -> Result<f64, CheckError> + Send + Sync + 'static,
|
|
||||||
) -> data::function::Function {
|
|
||||||
data::function::Function {
|
|
||||||
info: program::run::Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(Arc::new(|a, _i| two_tuple_to_num_impl_check(a, func_name))),
|
|
||||||
run: Arc::new(move |a, _i| {
|
|
||||||
two_tuple_to_num_impl_run(a, func_name, &func_ii, &func_if, &func_fi, &func_ff)
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn two_tuple_to_num_impl_check(a: &Type, func_name: &str) -> Result<Type, CheckError> {
|
|
||||||
let mut float = false;
|
|
||||||
for t in &a.types {
|
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
|
||||||
if t.0.len() != 2 {
|
|
||||||
return Err(format!("Called {func_name} with a tuple where len != 2").into());
|
|
||||||
}
|
|
||||||
for (t, side) in [(&t.0[0], "left"), (&t.0[1], "right")] {
|
|
||||||
for t in t.types.iter() {
|
|
||||||
if t.as_any().is::<data::float::FloatT>() {
|
|
||||||
float = true;
|
|
||||||
} else if !t.as_any().is::<data::int::IntT>() {
|
|
||||||
return Err(format!("Called {func_name}, but the {side} side of the tuple had type {t}, which isn't Int/Float.").into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(format!("Called {func_name} on a non-tuple").into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(if a.types.is_empty() {
|
|
||||||
Type::empty()
|
|
||||||
} else if float {
|
|
||||||
Type::new(data::float::FloatT)
|
|
||||||
} else {
|
|
||||||
Type::new(data::int::IntT)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn two_tuple_to_num_impl_run(
|
|
||||||
a: Data,
|
|
||||||
func_name: &'static str,
|
|
||||||
func_ii: &(impl Fn(isize, isize) -> Result<isize, CheckError> + Send + Sync),
|
|
||||||
func_if: &(impl Fn(isize, f64) -> Result<f64, CheckError> + Send + Sync),
|
|
||||||
func_fi: &(impl Fn(f64, isize) -> Result<f64, CheckError> + Send + Sync),
|
|
||||||
func_ff: &(impl Fn(f64, f64) -> Result<f64, CheckError> + Send + Sync),
|
|
||||||
) -> Result<Data, CheckError> {
|
|
||||||
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());
|
|
||||||
Ok(
|
|
||||||
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(func_ii(*l, *r)?))
|
|
||||||
}
|
|
||||||
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => {
|
|
||||||
Data::new(data::float::Float(func_if(*l, *r)?))
|
|
||||||
}
|
|
||||||
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => {
|
|
||||||
Data::new(data::float::Float(func_fi(*l, *r)?))
|
|
||||||
}
|
|
||||||
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => {
|
|
||||||
Data::new(data::float::Float(func_ff(*l, *r)?))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(format!(
|
|
||||||
"at least one of the arguments to {func_name} were neither an int nor a float"
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return Err(format!("argument to {func_name} was not a tuple").into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ltgtoe_function(
|
|
||||||
func_name: String,
|
|
||||||
op: impl Fn(IntOrFloatOrNothing, IntOrFloatOrNothing) -> bool + Send + Sync + 'static,
|
|
||||||
) -> data::function::Function {
|
|
||||||
data::function::Function {
|
|
||||||
info: program::run::Info::neverused(),
|
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
|
||||||
out: Ok(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?;
|
|
||||||
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 {
|
|
||||||
return Err(
|
|
||||||
"one of the (l/g)t[oe] function argument iterator elements were neither int nor float".into(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
if op(prev, new) {
|
|
||||||
prev = new;
|
|
||||||
} else {
|
|
||||||
return Ok(Data::new(data::bool::Bool(false)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Data::new(data::bool::Bool(true)))
|
|
||||||
}),
|
|
||||||
inner_statements: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum IntOrFloatOrNothing {
|
|
||||||
Nothing,
|
|
||||||
Int(isize),
|
|
||||||
Float(f64),
|
|
||||||
}
|
|
||||||
|
@ -20,45 +20,39 @@ impl Config {
|
|||||||
pub fn with_string(self) -> Self {
|
pub fn with_string(self) -> Self {
|
||||||
self.add_var(
|
self.add_var(
|
||||||
"trim".to_string(),
|
"trim".to_string(),
|
||||||
Data::new(func(|v: &str| Ok(v.trim().to_owned()))),
|
Data::new(func(|v: &str, _| Ok(v.trim().to_owned()))),
|
||||||
)
|
)
|
||||||
// .add_var("index_of".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_int(|v, p| v.find(p).map(|v| v as _))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"index_of".to_string(),
|
"index_of".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| {
|
Data::new(func(|(v, p): (&str, &str), _| {
|
||||||
Ok(OneOrNone(v.find(p).map(|v| v as isize)))
|
Ok(OneOrNone(v.find(p).map(|v| v as isize)))
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
// .add_var("index_of_rev".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_int(|v, p| v.rfind(p).map(|v| v as _) )))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"index_of_rev".to_string(),
|
"index_of_rev".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| {
|
Data::new(func(|(v, p): (&str, &str), _| {
|
||||||
Ok(OneOrNone(v.rfind(p).map(|v| v as isize)))
|
Ok(OneOrNone(v.rfind(p).map(|v| v as isize)))
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
// .add_var("starts_with".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_bool(|v, p| v.starts_with(p))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"starts_with".to_string(),
|
"starts_with".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| Ok(v.starts_with(p)))),
|
Data::new(func(|(v, p): (&str, &str), _| Ok(v.starts_with(p)))),
|
||||||
)
|
)
|
||||||
// .add_var("ends_with".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_bool(|v, p| v.ends_with(p))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"ends_with".to_string(),
|
"ends_with".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| Ok(v.ends_with(p)))),
|
Data::new(func(|(v, p): (&str, &str), _| Ok(v.ends_with(p)))),
|
||||||
)
|
)
|
||||||
// .add_var("str_split_once".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_string_string(|v, p| v.split_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"str_split_once".to_string(),
|
"str_split_once".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| {
|
Data::new(func(|(v, p): (&str, &str), _| {
|
||||||
Ok(AnyOrNone(
|
Ok(AnyOrNone(
|
||||||
v.split_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
|
v.split_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
|
||||||
))
|
))
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
// .add_var("str_split_once_rev".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_string_string(|v, p| v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"str_split_once_rev".to_string(),
|
"str_split_once_rev".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| {
|
Data::new(func(|(v, p): (&str, &str), _| {
|
||||||
Ok(AnyOrNone(
|
Ok(AnyOrNone(
|
||||||
v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
|
v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
|
||||||
))
|
))
|
||||||
@ -66,11 +60,10 @@ impl Config {
|
|||||||
)
|
)
|
||||||
.add_var(
|
.add_var(
|
||||||
"str_split".to_string(),
|
"str_split".to_string(),
|
||||||
Data::new(func(|(v, p): (&str, &str)| {
|
Data::new(func(|(v, p): (&str, &str), _| {
|
||||||
Ok(IterToList(v.split(p).map(|v| v.to_owned())))
|
Ok(IterToList(v.split(p).map(|v| v.to_owned())))
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
// .add_var("str_split".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_any(Type::new(super::with_list::ListT(Type::new(data::string::StringT))), |v, p| Ok(Data::new(super::with_list::List(v.split(p).map(|v| Arc::new(RwLock::new(Data::new(data::string::String(v.to_owned()))))).collect()))))))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"concat".to_string(),
|
"concat".to_string(),
|
||||||
Data::new(util::to_mers_func(
|
Data::new(util::to_mers_func(
|
||||||
@ -99,56 +92,9 @@ impl Config {
|
|||||||
|a| Ok(Data::new(data::string::String(a.get().to_string()))),
|
|a| Ok(Data::new(data::string::String(a.get().to_string()))),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
// .add_var("substring".to_string(), Data::new(util::to_mers_func(
|
|
||||||
// |a| {
|
|
||||||
// for t in a.types.iter() {
|
|
||||||
// if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
|
||||||
// if t.0.len() != 2 && t.0.len() != 3 {
|
|
||||||
// return Err(format!("cannot call substring with tuple argument of len != 3").into());
|
|
||||||
// }
|
|
||||||
// if !t.0[0].is_included_in_single(&data::string::StringT) {
|
|
||||||
// return Err(format!("cannot call substring with tuple argument that isn't (*string*, int, int)").into());
|
|
||||||
// }
|
|
||||||
// if !t.0[1].is_included_in_single(&data::int::IntT) {
|
|
||||||
// return Err(format!("cannot call substring with tuple argument that isn't (string, *int*, int)").into());
|
|
||||||
// }
|
|
||||||
// if t.0.len() > 2 && !t.0[2].is_included_in_single(&data::int::IntT) {
|
|
||||||
// return Err(format!("cannot call substring with tuple argument that isn't (string, int, *int*)").into());
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return Err(format!("cannot call substring with non-tuple argument.").into());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Ok(if a.types.is_empty() {
|
|
||||||
// Type::empty()
|
|
||||||
// } else {
|
|
||||||
// Type::new(data::string::StringT)
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// |a| {
|
|
||||||
// let tuple = a.get();
|
|
||||||
// let tuple = tuple.as_any().downcast_ref::<data::tuple::Tuple>().expect("called substring with non-tuple arg");
|
|
||||||
// let (s, start, end) = (&tuple.0[0], &tuple.0[1], tuple.0.get(2));
|
|
||||||
// let s = s.get();
|
|
||||||
// let s = &s.as_any().downcast_ref::<data::string::String>().unwrap().0;
|
|
||||||
// let start = start.get();
|
|
||||||
// let start = start.as_any().downcast_ref::<data::int::Int>().unwrap().0;
|
|
||||||
// let start = if start < 0 { s.len().saturating_sub(start.abs() as usize) } else { start as usize };
|
|
||||||
// let end = end
|
|
||||||
// .map(|end| end.get())
|
|
||||||
// .map(|end| end.as_any().downcast_ref::<data::int::Int>().unwrap().0)
|
|
||||||
// .map(|i| if i < 0 { s.len().saturating_sub(i.abs() as usize) } else { i as usize })
|
|
||||||
// .unwrap_or(usize::MAX);
|
|
||||||
// let end = end.min(s.len());
|
|
||||||
// if end < start {
|
|
||||||
// return Ok(Data::new(data::string::String(String::new())));
|
|
||||||
// }
|
|
||||||
// Ok(Data::new(data::string::String(s[start..end].to_owned())))
|
|
||||||
// })
|
|
||||||
// ))
|
|
||||||
.add_var(
|
.add_var(
|
||||||
"substring".to_string(),
|
"substring".to_string(),
|
||||||
Data::new(func(|v: OneOf<(&str, isize), (&str, isize, isize)>| {
|
Data::new(func(|v: OneOf<(&str, isize), (&str, isize, isize)>, _| {
|
||||||
let (s, start, end) = match v {
|
let (s, start, end) = match v {
|
||||||
OneOf::A((t, s)) => (t, s, None),
|
OneOf::A((t, s)) => (t, s, None),
|
||||||
OneOf::B((t, s, e)) => (t, s, Some(e)),
|
OneOf::B((t, s, e)) => (t, s, Some(e)),
|
||||||
|
Loading…
Reference in New Issue
Block a user