[no version bump yet] better and safer stdlib impl

only transformed configs/with_string so far,
but other configs/* should follow soon.
also, this will help with implementing
new stdlib functions in the future.
This commit is contained in:
Mark 2024-07-02 22:04:42 +02:00
parent 18cd3ee0ae
commit 50928cca1d
21 changed files with 841 additions and 184 deletions

View File

@ -1,3 +1,7 @@
# IN CODE
rm mers_lib/src/program/configs/util.rs
# Objects
```

View File

@ -15,7 +15,7 @@ default = ["colored-output"]
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
[dependencies]
mers_lib = "0.9.0"
# mers_lib = { path = "../mers_lib" }
# mers_lib = "0.9.0"
mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true }

View File

@ -30,7 +30,7 @@ fn run(src: String) -> Result<(), CheckError> {
)
.add_var(
"rust_func".to_owned(),
Data::new(data::function::Function::new(
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.

View File

@ -15,7 +15,10 @@ use super::{Data, MersData, MersType, Type};
pub struct Function {
pub info: Info,
pub info_check: Arc<Mutex<CheckInfo>>,
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
pub out: Result<
Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
Arc<Vec<(Type, Type)>>,
>,
pub run:
Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError> + Send + Sync>,
pub inner_statements: Option<(
@ -35,14 +38,26 @@ impl Clone for Function {
}
}
impl Function {
pub fn new(
pub fn new_static(
out: Vec<(Type, Type)>,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> Self {
Self {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
out: Err(Arc::new(out)),
run: Arc::new(move |a, _| run(a)),
inner_statements: None,
}
}
pub fn new_generic(
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> Self {
Self {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
out: Arc::new(move |a, _| out(a)),
out: Ok(Arc::new(move |a, _| out(a))),
run: Arc::new(move |a, _| run(a)),
inner_statements: None,
}
@ -51,7 +66,7 @@ impl Function {
Self {
info,
info_check: Arc::clone(&self.info_check),
out: Arc::clone(&self.out),
out: self.out.clone(),
run: Arc::clone(&self.run),
inner_statements: self
.inner_statements
@ -63,10 +78,7 @@ impl Function {
*self.info_check.lock().unwrap() = check;
}
pub fn check(&self, arg: &Type) -> Result<Type, CheckError> {
let lock = self.info_check.lock().unwrap();
let mut info = lock.clone();
drop(lock);
(self.out)(arg, &mut info)
self.get_as_type().o(arg)
}
pub fn run_mut(&mut self, arg: Data) -> Result<Data, CheckError> {
(self.run)(arg, &mut self.info)
@ -75,14 +87,23 @@ impl Function {
(self.run)(arg, &mut self.info.duplicate())
}
pub fn get_as_type(&self) -> FunctionT {
let out = Arc::clone(&self.out);
let info = Arc::clone(&self.info_check);
FunctionT(Ok(Arc::new(move |a| {
let lock = info.lock().unwrap();
let mut info = lock.clone();
drop(lock);
out(a, &mut info)
})))
match &self.out {
Ok(out) => {
let out = Arc::clone(out);
let info = self.info_check.lock().unwrap().clone();
FunctionT(Ok(Arc::new(move |a| out(a, &mut info.clone()))))
}
Err(types) => FunctionT(Err(Arc::clone(types))),
}
}
pub fn inner_statements(
&self,
) -> &Option<(
Arc<Box<dyn crate::program::run::MersStatement>>,
Arc<Box<dyn crate::program::run::MersStatement>>,
)> {
&self.inner_statements
}
}
@ -130,7 +151,7 @@ impl MersData for Function {
#[derive(Clone)]
pub struct FunctionT(
pub Result<Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>, Vec<(Type, Type)>>,
pub Result<Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>, Arc<Vec<(Type, Type)>>>,
);
impl FunctionT {
/// get output type

View File

@ -246,10 +246,13 @@ pub fn type_from_parsed(
})
.collect::<Result<_, _>>()?,
))),
ParsedType::Function(v) => as_type.add(Arc::new(data::function::FunctionT(Err(v
.iter()
ParsedType::Function(v) => {
as_type.add(Arc::new(data::function::FunctionT(Err(Arc::new(
v.iter()
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
.collect::<Result<_, CheckError>>()?)))),
.collect::<Result<_, CheckError>>()?,
)))))
}
ParsedType::Type(name) => match info
.scopes
.iter()

View File

@ -0,0 +1,90 @@
use std::sync::Arc;
use crate::{
data::{self, Data, MersData, Type},
errors::CheckError,
};
use super::{FromMersData, ToMersData};
pub fn func<I: FromMersData + 'static, O: ToMersData + 'static>(
f: fn(I) -> Result<O, CheckError>,
) -> data::function::Function {
Box::new(f).mers_func()
}
// fn this_works() {
// let cfg = ();
// // type: `(Int -> Float, Byte -> Int)`
// // todo: maybe add an Iterable<T> "type" that we can use like `[Itarable<Int>] (1, 2, 3)`
// cfg.add_var(
// "test".to_owned(),
// Data::new(
// TwoFuncs(
// OneFunc::new(|num: isize| Ok(num as f64 / 2.0)),
// OneFunc::new(|num: u8| Ok(num as isize)),
// )
// .to_mers_func(),
// ),
// );
// }
pub trait StaticMersFunc: Sized + 'static + Send + Sync {
fn types() -> Vec<(Type, Type)>;
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>>;
fn mers_func(self) -> data::function::Function {
data::function::Function::new_static(Self::types(), move |a| {
match self.run(a.get().as_ref()) {
Some(Ok(v)) => Ok(v),
Some(Err(e)) => Err(e),
None => Err(CheckError::from(format!(
"unexpected argument of type {}, expected {}",
a.get().as_type(),
Type::new(data::function::FunctionT(Err(Arc::new(Self::types()))))
))),
}
})
}
}
pub struct TwoFuncs<A: StaticMersFunc, B: StaticMersFunc>(pub A, pub B);
pub trait Func: Send + Sync + 'static {
type I: FromMersData;
type O: ToMersData;
fn run_func(&self, i: Self::I) -> Result<Self::O, CheckError>;
}
impl<I: FromMersData + 'static, O: ToMersData + 'static> Func for fn(I) -> Result<O, CheckError> {
type I = I;
type O = O;
fn run_func(&self, i: Self::I) -> Result<Self::O, CheckError> {
self(i)
}
}
impl<F: Func + ?Sized> StaticMersFunc for Box<F> {
fn types() -> Vec<(Type, Type)> {
vec![(F::I::as_type_from(), F::O::as_type_to())]
}
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>> {
F::I::try_represent(a, |v| v.map(|v| self.run_func(v).map(|v| v.represent())))
}
}
impl<A: StaticMersFunc, B: StaticMersFunc> StaticMersFunc for TwoFuncs<A, B> {
fn types() -> Vec<(Type, Type)> {
let mut o = A::types();
for t in B::types() {
if o.iter().any(|o| t.0.is_included_in(&o.0)) {
// other function fully covers this case already,
// ignore it in type signature as we will always call the first function instead of the 2nd one
} else {
o.push(t);
}
}
o
}
fn run(&self, a: &(impl MersData + ?Sized)) -> Option<Result<Data, CheckError>> {
self.0.run(a).or_else(|| self.1.run(a))
}
}

View File

@ -0,0 +1,453 @@
pub mod function;
use std::sync::{Arc, RwLock};
use crate::data::{self, Data, MersData, Type};
pub trait FromMersData: Sized {
fn as_type_from() -> Type;
fn can_represent(t: &Type) -> bool;
/// **NOTE: `f` may only used the passed value of type `Self` during the call to `f`**.
/// Storing the value anywhere, moving it to a thread or otherwise assuming that it lives longer than the function call
/// violates Rust's lifetime rules, but is allowed by the compiler because of some `unsafe` code which
/// calls `f` with a `Self` type with a lifetime that is incorrect on purpose (but seemingly necessary for this to work at all).
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O;
}
pub trait ToMersData {
/// what type this will become when `represent` is called
fn as_type_to() -> Type;
fn represent(self) -> Data;
}
/// Generates types like `(A)/()`. If `A` is a tuple-type, consider using `AnyOrNone` instead.
pub struct OneOrNone<A>(pub Option<A>);
/// Mainly used to generate types like `(A, B)/()` where `OneOrNone` would generate `((A, B))/()`, but can also generate `A/()`
pub struct AnyOrNone<A>(pub Option<A>);
impl<A: FromMersData> FromMersData for OneOrNone<A> {
fn as_type_from() -> Type {
Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![A::as_type_from()])),
Arc::new(data::tuple::TupleT(vec![])),
])
}
fn can_represent(t: &Type) -> bool {
t.one_tuple_possible_content()
.is_some_and(|t| A::can_represent(&t))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d
.as_any()
.downcast_ref::<data::tuple::Tuple>()
.filter(|v| v.0.len() <= 1)
{
if v.0.is_empty() {
f(Some(Self(None)))
} else {
A::try_represent(v.0[0].get().as_ref(), |v1| {
if let Some(va) = v1 {
f(Some(Self(Some(va))))
} else {
f(None)
}
})
}
} else {
f(None)
}
}
}
impl<A: ToMersData> ToMersData for OneOrNone<A> {
fn as_type_to() -> Type {
Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![A::as_type_to()])),
Arc::new(data::tuple::TupleT(vec![])),
])
}
fn represent(self) -> Data {
if let Some(v) = self.0 {
Data::one_tuple(v.represent())
} else {
Data::empty_tuple()
}
}
}
impl<A: FromMersData> FromMersData for AnyOrNone<A> {
fn as_type_from() -> Type {
Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![A::as_type_from()])),
Arc::new(data::tuple::TupleT(vec![])),
])
}
fn can_represent(t: &Type) -> bool {
t.one_tuple_possible_content()
.is_some_and(|t| A::can_represent(&t))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if d.as_any()
.downcast_ref::<data::tuple::Tuple>()
.is_some_and(|v| v.0.is_empty())
{
f(Some(Self(None)))
} else {
A::try_represent(d, |v1| {
if let Some(va) = v1 {
f(Some(Self(Some(va))))
} else {
f(None)
}
})
}
}
}
impl<A: ToMersData> ToMersData for AnyOrNone<A> {
fn as_type_to() -> Type {
let mut o = A::as_type_to();
o.add_all(&Type::empty_tuple());
o
}
fn represent(self) -> Data {
if let Some(v) = self.0 {
v.represent()
} else {
Data::empty_tuple()
}
}
}
pub enum OneOf<A, B> {
A(A),
B(B),
}
impl<A: FromMersData, B: FromMersData> FromMersData for OneOf<A, B> {
fn as_type_from() -> Type {
let mut o = A::as_type_from();
o.add_all(&B::as_type_from());
o
}
fn can_represent(t: &Type) -> bool {
A::can_represent(t) || B::can_represent(t)
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
A::try_represent(d, |v| {
if let Some(v) = v {
f(Some(OneOf::A(v)))
} else {
B::try_represent(d, |v| {
if let Some(v) = v {
f(Some(OneOf::B(v)))
} else {
f(None)
}
})
}
})
}
}
impl<A: ToMersData, B: ToMersData> ToMersData for OneOf<A, B> {
fn as_type_to() -> Type {
let mut o = A::as_type_to();
o.add_all(&B::as_type_to());
o
}
fn represent(self) -> Data {
match self {
Self::A(v) => v.represent(),
Self::B(v) => v.represent(),
}
}
}
pub struct IterToList<T: ToMersData, I: Iterator<Item = T>>(pub I);
impl<T: ToMersData, I: Iterator<Item = T>> ToMersData for IterToList<T, I> {
fn as_type_to() -> Type {
Type::new(super::with_list::ListT(T::as_type_to()))
}
fn represent(self) -> Data {
Data::new(super::with_list::List(
self.0
.map(|v| Arc::new(RwLock::new(v.represent())))
.collect(),
))
}
}
impl FromMersData for () {
fn as_type_from() -> Type {
Self::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_zero_tuple()
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
f(d.as_any()
.downcast_ref::<data::tuple::Tuple>()
.is_some_and(|v| v.0.is_empty())
.then_some(()))
}
}
impl ToMersData for () {
fn as_type_to() -> Type {
Type::empty_tuple()
}
fn represent(self) -> Data {
Data::empty_tuple()
}
}
impl<A: FromMersData> FromMersData for (A,) {
fn as_type_from() -> Type {
Type::new(data::tuple::TupleT(vec![A::as_type_from()]))
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Self::as_type_from())
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d
.as_any()
.downcast_ref::<data::tuple::Tuple>()
.filter(|v| v.0.len() == 1)
{
A::try_represent(v.0[0].get().as_ref(), |v1| {
if let Some(va) = v1 {
f(Some((va,)))
} else {
f(None)
}
})
} else {
f(None)
}
}
}
impl<A: ToMersData> ToMersData for (A,) {
fn as_type_to() -> Type {
Type::new(data::tuple::TupleT(vec![A::as_type_to()]))
}
fn represent(self) -> Data {
Data::new(data::tuple::Tuple(vec![self.0.represent()]))
}
}
impl<A: FromMersData, B: FromMersData> FromMersData for (A, B) {
fn as_type_from() -> Type {
Type::new(data::tuple::TupleT(vec![
A::as_type_from(),
B::as_type_from(),
]))
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Self::as_type_from())
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d
.as_any()
.downcast_ref::<data::tuple::Tuple>()
.filter(|v| v.0.len() == 2)
{
A::try_represent(v.0[0].get().as_ref(), |v1| {
if let Some(va) = v1 {
B::try_represent(v.0[1].get().as_ref(), |v2| {
if let Some(vb) = v2 {
f(Some((va, vb)))
} else {
f(None)
}
})
} else {
f(None)
}
})
} else {
f(None)
}
}
}
impl<A: ToMersData, B: ToMersData> ToMersData for (A, B) {
fn as_type_to() -> Type {
Type::new(data::tuple::TupleT(vec![A::as_type_to(), B::as_type_to()]))
}
fn represent(self) -> Data {
Data::new(data::tuple::Tuple(vec![
self.0.represent(),
self.1.represent(),
]))
}
}
impl<A: FromMersData, B: FromMersData, C: FromMersData> FromMersData for (A, B, C) {
fn as_type_from() -> Type {
Type::new(data::tuple::TupleT(vec![
A::as_type_from(),
B::as_type_from(),
C::as_type_from(),
]))
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Self::as_type_from())
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d
.as_any()
.downcast_ref::<data::tuple::Tuple>()
.filter(|v| v.0.len() == 2)
{
A::try_represent(v.0[0].get().as_ref(), |v1| {
if let Some(va) = v1 {
B::try_represent(v.0[1].get().as_ref(), |v2| {
if let Some(vb) = v2 {
C::try_represent(v.0[2].get().as_ref(), |v3| {
if let Some(vc) = v3 {
f(Some((va, vb, vc)))
} else {
f(None)
}
})
} else {
f(None)
}
})
} else {
f(None)
}
})
} else {
f(None)
}
}
}
impl<A: ToMersData, B: ToMersData, C: ToMersData> ToMersData for (A, B, C) {
fn as_type_to() -> Type {
Type::new(data::tuple::TupleT(vec![
A::as_type_to(),
B::as_type_to(),
C::as_type_to(),
]))
}
fn represent(self) -> Data {
Data::new(data::tuple::Tuple(vec![
self.0.represent(),
self.1.represent(),
self.2.represent(),
]))
}
}
impl FromMersData for bool {
fn as_type_from() -> Type {
Self::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Type::new(data::bool::BoolT))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d.as_any().downcast_ref::<data::bool::Bool>() {
f(Some(v.0))
} else {
f(None)
}
}
}
impl ToMersData for bool {
fn as_type_to() -> Type {
Type::new(data::bool::BoolT)
}
fn represent(self) -> Data {
Data::new(data::bool::Bool(self))
}
}
impl FromMersData for u8 {
fn as_type_from() -> Type {
Self::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Type::new(data::byte::ByteT))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d.as_any().downcast_ref::<data::byte::Byte>() {
f(Some(v.0))
} else {
f(None)
}
}
}
impl ToMersData for u8 {
fn as_type_to() -> Type {
Type::new(data::byte::ByteT)
}
fn represent(self) -> Data {
Data::new(data::byte::Byte(self))
}
}
impl FromMersData for isize {
fn as_type_from() -> Type {
Self::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Type::new(data::int::IntT))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d.as_any().downcast_ref::<data::int::Int>() {
f(Some(v.0))
} else {
f(None)
}
}
}
impl ToMersData for isize {
fn as_type_to() -> Type {
Type::new(data::int::IntT)
}
fn represent(self) -> Data {
Data::new(data::int::Int(self))
}
}
impl FromMersData for f64 {
fn as_type_from() -> Type {
Self::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Type::new(data::float::FloatT))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d.as_any().downcast_ref::<data::float::Float>() {
f(Some(v.0))
} else {
f(None)
}
}
}
impl ToMersData for f64 {
fn as_type_to() -> Type {
Type::new(data::float::FloatT)
}
fn represent(self) -> Data {
Data::new(data::float::Float(self))
}
}
impl FromMersData for &str {
fn as_type_from() -> Type {
String::as_type_to()
}
fn can_represent(t: &Type) -> bool {
t.is_included_in(&Type::new(data::string::StringT))
}
fn try_represent<O, F: FnOnce(Option<Self>) -> O>(d: &(impl MersData + ?Sized), f: F) -> O {
if let Some(v) = d.as_any().downcast_ref::<data::string::String>() {
let v = v.0.as_str();
unsafe { f(Some(std::ptr::from_ref(v).as_ref().unwrap())) }
} else {
f(None)
}
}
}
impl ToMersData for String {
fn as_type_to() -> Type {
Type::new(data::string::StringT)
}
fn represent(self) -> Data {
Data::new(data::string::String(self))
}
}

View File

@ -7,6 +7,7 @@ use crate::{
program::run::CheckInfo,
};
pub mod gen;
pub mod util;
pub mod with_base;
pub mod with_command_running;

View File

@ -13,7 +13,7 @@ pub fn to_mers_func(
data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(Info::neverused())),
out: Arc::new(move |a, _| out(a)),
out: Ok(Arc::new(move |a, _| out(a))),
run: Arc::new(move |a, _| run(a)),
inner_statements: None,
}
@ -41,16 +41,7 @@ pub fn to_mers_func_with_in_out_types(
out_type: Type,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func(
move |a| {
if a.is_included_in(&in_type) {
Ok(out_type.clone())
} else {
Err(format!("Function argument must be {in_type}, but was {a}.").into())
}
},
run,
)
data::function::Function::new_static(vec![(in_type, out_type)], run)
}
pub fn to_mers_func_concrete_string_to_any(

View File

@ -29,7 +29,7 @@ impl Config {
.add_var("lock_update".to_string(), Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() == 2 {
@ -61,7 +61,7 @@ impl Config {
}
}
Ok(Type::empty_tuple())
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let a = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -77,14 +77,14 @@ impl Config {
.add_var("sleep".to_string(), Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if a.is_included_in(&Type::newm(vec![
out: Ok(Arc::new(|a, _i| if a.is_included_in(&Type::newm(vec![
Arc::new(data::int::IntT),
Arc::new(data::float::FloatT),
])) {
Ok(Type::empty_tuple())
} else {
Err(format!("cannot call sleep with non-int or non-float argument.").into())
}),
})),
run: Arc::new(|a, i| {
let a = a.get();
let mut sleep_dur = if let Some(data::int::Int(n)) = a.as_any().downcast_ref() {
@ -106,11 +106,11 @@ impl Config {
.add_var("exit".to_string(), Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if a.is_included_in_single(&data::int::IntT) {
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));
}),
@ -119,11 +119,11 @@ impl Config {
.add_var("panic".to_string(), Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if a.is_included_in_single(&data::string::StringT) {
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
@ -141,14 +141,14 @@ impl Config {
Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
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() {
return Err(format!("cannot get length of {t} (must be a tuple, string or iterable)").into());
}
}
Ok(Type::new(data::int::IntT))
}),
})),
run: Arc::new(|a, _i| {
Ok(Data::new(data::int::Int(if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
t.0.len() as _
@ -169,14 +169,14 @@ impl Config {
Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
for t in &a.types {
if t.iterable().is_none() {
return Err(format!("called eq on non-iterable").into())
}
}
Ok(Type::new(data::bool::BoolT))
}),
})),
run: Arc::new(|a, _i| {
Ok(Data::new(data::bool::Bool(if let Some(mut i) = a.get().iterable() {
if let Some(f) = i.next() {
@ -205,7 +205,7 @@ impl Config {
Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| Ok(Type::new(data::reference::ReferenceT(a.clone())))),
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())))))
}),
@ -217,8 +217,8 @@ impl Config {
Data::new(data::function::Function {
info: Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into())
}),
out: Ok(Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into())
})),
run: Arc::new(|a, _i| {
if let Some(r) = a
.get()

View File

@ -29,7 +29,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![
@ -42,7 +42,7 @@ impl Config {
} else {
return Err(format!("run_command called with invalid arguments (must be (String, Iter<String>))").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -84,7 +84,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.types.iter().all(|t| t.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) {
Ok(Type::newm(vec![
Arc::new(ChildProcessT),
@ -93,7 +93,7 @@ impl Config {
} else {
return Err(format!("spawn_command called with invalid arguments (must be (String, Iter<String>))").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let cmd = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -128,7 +128,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::bool::BoolT)])),
@ -137,7 +137,7 @@ impl Config {
} else {
return Err(format!("childproc_exited called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
@ -156,7 +156,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::int::IntT),
@ -166,7 +166,7 @@ impl Config {
} else {
return Err(format!("childproc_await called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
@ -189,13 +189,13 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.types.iter().all(|a| a.as_any().downcast_ref::<data::tuple::TupleT>().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) {
Ok(Type::new(data::bool::BoolT))
} else {
return Err(format!("childproc_write_bytes called on non-`(ChildProcess, Iter<Byte>)` type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let tuple = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -218,13 +218,13 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) {
Ok(Type::new(data::bool::BoolT))
} else {
return Err(format!("childproc_write_string called on non-`(ChildProcess, String)` type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let tuple = a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -247,7 +247,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
@ -256,7 +256,7 @@ impl Config {
} else {
return Err(format!("childproc_read_byte called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
@ -276,7 +276,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::byte::ByteT)])),
@ -285,7 +285,7 @@ impl Config {
} else {
return Err(format!("childproc_readerr_byte called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
@ -305,7 +305,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
@ -314,7 +314,7 @@ impl Config {
} else {
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
@ -334,7 +334,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in_single(&ChildProcessT) {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
@ -343,7 +343,7 @@ impl Config {
} else {
return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();

View File

@ -15,7 +15,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let mut out = Type::empty();
for a in a.types.iter() {
if let Some(t) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -45,7 +45,7 @@ impl Config {
Arc::new(data::tuple::TupleT(vec![out])),
Arc::new(data::tuple::TupleT(vec![])),
]))
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
if let (Some(v), Some(i)) = (a.get(0), a.get(1)) {

View File

@ -49,7 +49,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
for a in &a.types {
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
@ -84,7 +84,7 @@ impl Config {
}
}
Ok(Type::empty_tuple())
}),
})),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -133,14 +133,14 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let data = if let Some(a) = a.iterable() {
a
} else {
return Err(format!("cannot call enumerate on non-iterable type {a}.").into());
};
Ok(Type::new(IterT::new(ItersT::Enumerate, data)?))
}),
})),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
inner_statements: None,
}),
@ -150,14 +150,14 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let data = if let Some(a) = a.iterable() {
a
} else {
return Err(format!("cannot call chain on non-iterable type {a}.").into());
};
Ok(Type::new(IterT::new(ItersT::Chained, data)?))
}),
})),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
inner_statements: None,
}),
@ -202,7 +202,7 @@ fn genfunc_iter_and_func(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, _i| iter_out_arg(a, name, |f| ft(f))),
out: Ok(Arc::new(move |a, _i| iter_out_arg(a, name, |f| ft(f)))),
run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -256,7 +256,9 @@ 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())),
out: Arc::new(move |a, _i| iter_out_arg(a, name, |f: &T| ft(f), type_sample)),
out: Ok(Arc::new(move |a, _i| {
iter_out_arg(a, name, |f: &T| ft(f), type_sample)
})),
run: Arc::new(move |a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -525,7 +527,7 @@ fn genfunc_iter_in_val_out(
Function {
info: crate::info::Info::neverused(),
info_check: Arc::new(Mutex::new(crate::info::Info::neverused())),
out: Arc::new(move |a, _i| {
out: Ok(Arc::new(move |a, _i| {
if let Some(iter_over) = a.iterable() {
if iter_over.is_included_in_single(&iter_type) {
Ok(out_type.clone())
@ -535,7 +537,7 @@ fn genfunc_iter_in_val_out(
} else {
Err(format!("Cannot call function {name} on non-iterable type {a}.").into())
}
}),
})),
run: Arc::new(run),
inner_statements: None,
}

View File

@ -34,7 +34,7 @@ impl Config {
.add_var("get_mut".to_string(), Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let mut out = Type::empty_tuple();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -71,7 +71,7 @@ impl Config {
}
}
Ok(out)
}),
})),
run: Arc::new(|a, _i| {
let t = a.get();
let t = t.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -103,7 +103,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if let Some(a) = a.dereference() {
let mut out = Type::empty();
for t in a.types.iter() {
@ -122,7 +122,7 @@ impl Config {
} else {
return Err(format!("pop: not a reference: {a}").into());
}
}),
})),
run: Arc::new(|a, _i| {
Ok(match a
.get()
@ -151,7 +151,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() != 2 {
@ -186,7 +186,7 @@ impl Config {
}
}
Ok(Type::empty_tuple())
}),
})),
run: Arc::new(|a, _i| {
let tuple = a.get();
let tuple = tuple.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
@ -214,7 +214,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if let Some(v) = a.iterable() {
Ok(Type::new(ListT(v)))
} else {
@ -222,7 +222,7 @@ impl Config {
"cannot iterate over type {a}"
).into())
}
}),
})),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
Ok(Data::new(List(i.map(|v| Ok::<_, CheckError>(Arc::new(RwLock::new(v?)))).collect::<Result<_, _>>()?)))

View File

@ -73,7 +73,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
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)])),
@ -82,7 +82,7 @@ impl Config {
} else {
Err(format!("parse_float called on non-string type").into())
}
}),
})),
run: Arc::new(|a, _i| {
Ok(
if let Ok(n) = a
@ -107,7 +107,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
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)])),
@ -116,7 +116,7 @@ impl Config {
} else {
Err(format!("parse_float called on non-string type").into())
}
}),
})),
run: Arc::new(|a, _i| {
Ok(
if let Ok(n) = a
@ -141,7 +141,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_included_in(&Type::newm(vec![
Arc::new(data::int::IntT),
Arc::new(data::float::FloatT),
@ -150,7 +150,7 @@ impl Config {
} 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>() {
@ -257,7 +257,7 @@ fn num_iter_to_num(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, _i| {
out: Ok(Arc::new(move |a, _i| {
if let Some(a) = a.iterable() {
let int_type = Type::new(data::int::IntT);
if a.is_included_in(&int_type) {
@ -281,7 +281,7 @@ fn num_iter_to_num(
} else {
Err(format!("argument passed to {func_name} must be an iterator").into())
}
}),
})),
run: Arc::new(move |a, _i| {
let mut out = init;
for v in a.get().iterable().unwrap() {
@ -322,7 +322,7 @@ fn two_num_tuple_to_num(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| two_tuple_to_num_impl_check(a, func_name)),
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)
}),
@ -408,7 +408,7 @@ fn ltgtoe_function(
data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, _i| {
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),
@ -422,7 +422,7 @@ fn ltgtoe_function(
} 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() {

View File

@ -32,7 +32,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(f) = t.executable() {
@ -45,7 +45,7 @@ impl Config {
}
}
Ok(Type::new(ThreadT(out)))
}),
})),
run: Arc::new(|a, _i| {
Ok(Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn(
move || a.get().execute(Data::empty_tuple()).unwrap(),
@ -57,14 +57,14 @@ impl Config {
.add_var("thread_finished".to_string(), Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
for t in a.types.iter() {
if !t.as_any().is::<ThreadT>() {
return Err(CheckError::new().msg_str(format!("Cannot call thread_finished on a value of type {t}, which isn't a thread but part of the argument {a}.")));
}
}
Ok(Type::new(data::bool::BoolT))
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let t = a.as_any().downcast_ref::<Thread>().unwrap().0.lock().unwrap();
@ -78,7 +78,7 @@ impl Config {
.add_var("thread_await".to_string(), Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
let mut out = Type::empty();
for t in a.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<ThreadT>() {
@ -88,7 +88,7 @@ impl Config {
}
}
Ok(out)
}),
})),
run: Arc::new(|a, _i| {
let a = a.get();
let mut t = a.as_any().downcast_ref::<Thread>().unwrap().0.lock().unwrap();

View File

@ -24,7 +24,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
out: Ok(Arc::new(|a, _i| {
if a.is_zero_tuple() {
Ok(Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])),
@ -36,7 +36,7 @@ impl Config {
(a.to_string(), Some(EColor::FunctionArgument)),
]))
}
}),
})),
run: Arc::new(|_a, _i| {
Ok(if let Some(Ok(line)) = std::io::stdin().lines().next() {
Data::one_tuple(Data::new(data::string::String(line)))
@ -52,7 +52,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| Ok(a.clone())),
out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
run: Arc::new(|a, _i| {
let a2 = a.get();
eprintln!("{} :: {}", a2.as_type(), a2);
@ -67,7 +67,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
eprint!("{}", a.get());
_ = std::io::stderr().lock().flush();
@ -81,7 +81,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
eprintln!("{}", a.get());
Ok(Data::empty_tuple())
@ -94,7 +94,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
print!("{}", a.get());
_ = std::io::stdout().lock().flush();
@ -108,7 +108,7 @@ impl Config {
Data::new(data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, _i| {
println!("{}", a.get());
Ok(Data::empty_tuple())

View File

@ -1,8 +1,9 @@
use std::sync::{Arc, RwLock};
use crate::data::{self, Data, Type};
use super::{util, Config};
use super::{
gen::{function::func, AnyOrNone, IterToList, OneOf, OneOrNone},
util, Config,
};
impl Config {
/// `trim: fn` removes leading and trailing whitespace from a string
@ -17,72 +18,161 @@ impl Config {
/// `to_string: fn` turns any argument into a (more or less useful) string representation
/// `concat: fn` concatenates all arguments given to it. arg must be an enumerable
pub fn with_string(self) -> Self {
self
.add_var("trim".to_string(), Data::new(util::to_mers_func_concrete_string_to_string(|v| 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("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("starts_with".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_bool(|v, p| 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("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("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("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("concat".to_string(), Data::new(util::to_mers_func(
|a| if a.iterable().is_some() {
self.add_var(
"trim".to_string(),
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(
"index_of".to_string(),
Data::new(func(|(v, p): (&str, &str)| {
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(
"index_of_rev".to_string(),
Data::new(func(|(v, p): (&str, &str)| {
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(
"starts_with".to_string(),
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(
"ends_with".to_string(),
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(
"str_split_once".to_string(),
Data::new(func(|(v, p): (&str, &str)| {
Ok(AnyOrNone(
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(
"str_split_once_rev".to_string(),
Data::new(func(|(v, p): (&str, &str)| {
Ok(AnyOrNone(
v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
))
})),
)
.add_var(
"str_split".to_string(),
Data::new(func(|(v, p): (&str, &str)| {
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(
"concat".to_string(),
Data::new(util::to_mers_func(
|a| {
if a.iterable().is_some() {
Ok(Type::new(data::string::StringT))
} else {
Err(format!("concat called on non-iterable type {a}").into())
}
},
|a| Ok(Data::new(data::string::String(a.get().iterable().unwrap().map(|v| v.map(|v| v.get().to_string())).collect::<Result<_, _>>()?)))),
))
.add_var("to_string".to_string(), Data::new(util::to_mers_func(|_a| Ok(Type::new(data::string::StringT)),
|a| Ok(Data::new(data::string::String(a.get().to_string())))
|a| {
Ok(Data::new(data::string::String(
a.get()
.iterable()
.unwrap()
.map(|v| v.map(|v| v.get().to_string()))
.collect::<Result<_, _>>()?,
)))
.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 };
)),
)
.add_var(
"to_string".to_string(),
Data::new(util::to_mers_func(
|_a| Ok(Type::new(data::string::StringT)),
|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(
"substring".to_string(),
Data::new(func(|v: OneOf<(&str, isize), (&str, isize, isize)>| {
let (s, start, end) = match v {
OneOf::A((t, s)) => (t, s, None),
OneOf::B((t, s, e)) => (t, s, Some(e)),
};
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 })
.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())));
return Ok(String::new());
}
Ok(Data::new(data::string::String(s[start..end].to_owned())))
})
))
Ok(s[start..end].to_owned())
})),
)
}
}

View File

@ -38,10 +38,10 @@ impl MersStatement for Function {
func_no_info: data::function::Function {
info: program::run::Info::neverused(),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, i| {
out: Ok(Arc::new(move |a, i| {
arg2.check(i, Some(a))?;
Ok(run2.check(i, None)?)
}),
})),
run: Arc::new(move |arg, info| {
data::defs::assign(&arg, &arg_target.run(info)?);
run.run(info)

View File

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

View File

@ -34,7 +34,7 @@ impl MersStatement for Function {
self.pos_in_src.clone()
}
fn inner_statements(&self) -> Vec<&dyn MersStatement> {
if let Some((a, b)) = &self.func_no_info.inner_statements {
if let Some((a, b)) = &self.func_no_info.inner_statements() {
vec![a.as_ref().as_ref(), b.as_ref().as_ref()]
} else {
vec![]