mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-29 01:16:53 +01:00
the math does math... at compile time, in types
This commit is contained in:
@@ -379,27 +379,33 @@ impl ToMersData for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromMersData for isize {
|
||||
/// An integer within the range `N..=M`
|
||||
pub struct IntR<const N: isize, const M: isize>(pub isize);
|
||||
impl<const N: isize, const M: isize> FromMersData for IntR<N, M> {
|
||||
fn as_type_from() -> Type {
|
||||
Self::as_type_to()
|
||||
}
|
||||
fn can_represent(t: &Type) -> bool {
|
||||
t.is_included_in(&Type::new(data::int::IntT))
|
||||
t.is_included_in(&Type::new(data::int::IntT(N, M)))
|
||||
}
|
||||
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))
|
||||
if N <= v.0 && v.0 <= M {
|
||||
f(Some(Self(v.0)))
|
||||
} else {
|
||||
f(None)
|
||||
}
|
||||
} else {
|
||||
f(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToMersData for isize {
|
||||
impl<const N: isize, const M: isize> ToMersData for IntR<N, M> {
|
||||
fn as_type_to() -> Type {
|
||||
Type::new(data::int::IntT)
|
||||
Type::new(data::int::IntT(N, M))
|
||||
}
|
||||
fn represent(self) -> Data {
|
||||
Data::new(data::int::Int(self))
|
||||
Data::new(data::int::Int(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersData, Type},
|
||||
data::{
|
||||
self,
|
||||
int::{INT_MAX, INT_MIN},
|
||||
Data, MersData, Type,
|
||||
},
|
||||
errors::CheckError,
|
||||
info::Local,
|
||||
program::run::{CheckInfo, CheckLocalGlobalInfo, RunLocalGlobalInfo},
|
||||
@@ -92,7 +96,42 @@ impl Config {
|
||||
.types
|
||||
.insert("Bool".to_owned(), Ok(Arc::new(data::bool::bool_type())));
|
||||
init_d!(data::byte::ByteT);
|
||||
init_d!(data::int::IntT);
|
||||
info_check.scopes.last_mut().unwrap().types.insert(
|
||||
"Int".to_owned(),
|
||||
// Ok(Arc::new(data::Type::new(data::int::INT_T_ALL))),
|
||||
Err(Arc::new(|range, _| {
|
||||
Ok(Arc::new(Type::new({
|
||||
let range = range.trim();
|
||||
if range.is_empty() {
|
||||
data::int::IntT(INT_MIN, INT_MAX)
|
||||
} else if let Some((min, max)) = range.split_once("..") {
|
||||
let (min, max) = (min.trim(), max.trim());
|
||||
let min = if min.is_empty() {
|
||||
data::int::INT_MIN
|
||||
} else if let Ok(v) = min.parse() {
|
||||
v
|
||||
} else {
|
||||
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: min was present but not a valid integer.")));
|
||||
};
|
||||
let max = if max.is_empty() {
|
||||
data::int::INT_MAX
|
||||
} else if let Ok(v) = max.parse() {
|
||||
v
|
||||
} else {
|
||||
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: max was present but not a valid integer.")));
|
||||
};
|
||||
if min > max {
|
||||
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: min ({min}) must be smaller than or equal to max ({max}). Did you mean `Int<{max}..{min}>`?")));
|
||||
}
|
||||
crate::data::int::IntT(min, max)
|
||||
} else if let Ok(v) = range.parse() {
|
||||
crate::data::int::IntT(v, v)
|
||||
} else {
|
||||
return Err(CheckError::new().msg_str(format!("In type `Int<{range}>`: Invalid range. Either use `Int` (or `Int<>` or `Int<..>`) for the entire integer range, `Int<n>` for a specific number, `Int<n..>` for all numbers `>=n`, `Int<..m>` for all numbers `<=m`, or `Int<n..m>` for all numbers `>=n` and `<= m`.")));
|
||||
}
|
||||
})))
|
||||
})),
|
||||
);
|
||||
init_d!(data::float::FloatT);
|
||||
init_d!(data::string::StringT);
|
||||
Self {
|
||||
|
||||
@@ -4,7 +4,12 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
data::{self, bool::bool_type, Data, MersTypeWInfo, Type},
|
||||
data::{
|
||||
self,
|
||||
bool::bool_type,
|
||||
int::{INT_MAX, INT_MIN},
|
||||
Data, MersTypeWInfo, Type,
|
||||
},
|
||||
errors::CheckError,
|
||||
program::run::{CheckInfo, Info},
|
||||
};
|
||||
@@ -12,7 +17,7 @@ use crate::{
|
||||
use super::{
|
||||
gen::{
|
||||
function::{func, func_end, func_err},
|
||||
OneOf,
|
||||
IntR, OneOf,
|
||||
},
|
||||
Config,
|
||||
};
|
||||
@@ -75,9 +80,9 @@ impl Config {
|
||||
}),
|
||||
inner_statements: None,
|
||||
})
|
||||
.add_var("sleep", func(|dur: OneOf<isize, f64>, i| {
|
||||
.add_var("sleep", func(|dur: OneOf<IntR<0, INT_MAX>, f64>, i| {
|
||||
let mut sleep_dur = match dur {
|
||||
OneOf::A(dur) => Duration::from_secs(dur.max(0).try_into().unwrap_or(u64::MAX)),
|
||||
OneOf::A(dur) => Duration::from_secs(dur.0.max(0).try_into().unwrap_or(u64::MAX)),
|
||||
OneOf::B(dur) => Duration::from_secs_f64(dur.max(0.0)),
|
||||
};
|
||||
// limit how long sleep can take
|
||||
@@ -87,8 +92,8 @@ impl Config {
|
||||
std::thread::sleep(sleep_dur);
|
||||
Ok(())
|
||||
}))
|
||||
.add_var("exit", func_end(|code: isize, _| {
|
||||
std::process::exit(code.try_into().unwrap_or(255));
|
||||
.add_var("exit", func_end(|code: IntR<INT_MIN, INT_MAX>, _| {
|
||||
std::process::exit(code.0.try_into().unwrap_or(255));
|
||||
}))
|
||||
.add_var("panic", func_err(|message: &str, _| {
|
||||
CheckError::from(message)
|
||||
@@ -104,18 +109,17 @@ impl Config {
|
||||
return Err(format!("cannot get length of {} (must be a tuple, string or iterable)", t.with_info(i)).into());
|
||||
}
|
||||
}
|
||||
Ok(Type::new(data::int::IntT))
|
||||
Ok(Type::new(data::int::IntT(0, INT_MAX)))
|
||||
})),
|
||||
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 _
|
||||
t.0.len().try_into().unwrap_or(INT_MAX)
|
||||
} else if let Some(s) = a.get().as_any().downcast_ref::<data::string::String>() {
|
||||
s.0.len() as _
|
||||
s.0.len().try_into().unwrap_or(INT_MAX)
|
||||
} else if let Some(i) = a.get().iterable() {
|
||||
// -1 if more elements than isize can represent
|
||||
i.take(isize::MAX as usize + 1).count().try_into().unwrap_or(-1)
|
||||
i.count().try_into().unwrap_or(INT_MAX)
|
||||
} 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, a string, or something iterable.".into());
|
||||
})))
|
||||
}),
|
||||
inner_statements: None,
|
||||
|
||||
@@ -6,7 +6,12 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
data::{self, object::ObjectFieldsMap, Data, MersData, MersDataWInfo, MersType, Type},
|
||||
data::{
|
||||
self,
|
||||
int::{INT_MAX, INT_MIN},
|
||||
object::ObjectFieldsMap,
|
||||
Data, MersData, MersDataWInfo, MersType, Type,
|
||||
},
|
||||
errors::CheckError,
|
||||
info::DisplayInfo,
|
||||
program::{self, run::CheckInfo},
|
||||
@@ -34,7 +39,7 @@ impl Config {
|
||||
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![
|
||||
Type::newm(vec![Arc::new(data::int::IntT), Arc::new(data::bool::TrueT), Arc::new(data::bool::FalseT)]),
|
||||
Type::newm(vec![Arc::new(data::int::IntT(INT_MIN, INT_MAX)), Arc::new(data::bool::TrueT), Arc::new(data::bool::FalseT)]),
|
||||
Type::new(data::string::StringT),
|
||||
Type::new(data::string::StringT),
|
||||
])),
|
||||
@@ -160,7 +165,7 @@ impl Config {
|
||||
out: Ok(Arc::new(|a, i| {
|
||||
if a.is_included_in_single(&ChildProcessT) {
|
||||
Ok(Type::newm(vec![
|
||||
Arc::new(data::int::IntT),
|
||||
Arc::new(data::int::IntT(INT_MIN, INT_MAX)),
|
||||
Arc::new(data::bool::TrueT),
|
||||
Arc::new(data::bool::FalseT),
|
||||
Arc::new(data::tuple::TupleT(vec![])),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersTypeWInfo, Type},
|
||||
data::{self, int::INT_MAX, Data, MersTypeWInfo, Type},
|
||||
program::{self, run::CheckInfo},
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ impl Config {
|
||||
if t.0.len() != 2 {
|
||||
return Err(format!("called get on tuple with len != 2").into());
|
||||
}
|
||||
if !t.0[1].is_included_in_single(&data::int::IntT) {
|
||||
if !t.0[1].is_included_in_single(&data::int::IntT(0, INT_MAX)) {
|
||||
return Err(format!(
|
||||
"called get with non-int index of type {}",
|
||||
t.0[1].with_info(i)
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{
|
||||
data::{
|
||||
self,
|
||||
function::{Function, FunctionT},
|
||||
int::INT_MAX,
|
||||
Data, MersData, MersType, MersTypeWInfo, Type,
|
||||
},
|
||||
errors::CheckError,
|
||||
@@ -128,8 +129,8 @@ impl Config {
|
||||
genfunc_iter_and_func("map_while", ItersT::MapWhile, Iters::MapWhile),
|
||||
)
|
||||
.add_var("take", genfunc_iter_and_arg("take", |_: &data::int::IntT| ItersT::Take, |v: &data::int::Int| {
|
||||
Iters::Take(v.0.max(0) as _)
|
||||
}, &data::int::IntT))
|
||||
Iters::Take(v.0.max(0).try_into().unwrap_or(usize::MAX))
|
||||
}, &data::int::IntT(0, INT_MAX)))
|
||||
.add_var(
|
||||
"enumerate",
|
||||
data::function::Function {
|
||||
@@ -463,7 +464,7 @@ impl IterT {
|
||||
}
|
||||
ItersT::Take => data.clone(),
|
||||
ItersT::Enumerate => Type::new(data::tuple::TupleT(vec![
|
||||
Type::new(data::int::IntT),
|
||||
Type::new(data::int::IntT(0, INT_MAX)),
|
||||
data.clone(),
|
||||
])),
|
||||
ItersT::Chained => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersData, MersType, MersTypeWInfo, Type},
|
||||
data::{self, int::INT_MAX, Data, MersData, MersType, MersTypeWInfo, Type},
|
||||
errors::CheckError,
|
||||
info::DisplayInfo,
|
||||
parsing::{statements::to_string_literal, Source},
|
||||
@@ -41,7 +41,7 @@ impl Config {
|
||||
"get_mut: argument must be a 2-tuple `(&List<_>, Int)`."
|
||||
).into());
|
||||
}
|
||||
if t.0[1].is_included_in_single(&data::int::IntT) {
|
||||
if t.0[1].is_included_in_single(&data::int::IntT(0, INT_MAX)) {
|
||||
if let Some(t) = t.0[0].dereference() {
|
||||
for t in t.types.iter() {
|
||||
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,11 @@
|
||||
use crate::data::{self, Data, MersDataWInfo, Type};
|
||||
use crate::data::{
|
||||
self,
|
||||
int::{INT_MAX, INT_MIN},
|
||||
Data, MersDataWInfo, Type,
|
||||
};
|
||||
|
||||
use super::{
|
||||
gen::{function::func, AnyOrNone, IterToList, OneOf, OneOrNone},
|
||||
gen::{function::func, AnyOrNone, IntR, IterToList, OneOf, OneOrNone},
|
||||
util, Config,
|
||||
};
|
||||
|
||||
@@ -21,11 +25,17 @@ impl Config {
|
||||
self.add_var("trim", func(|v: &str, _| Ok(v.trim().to_owned())))
|
||||
.add_var(
|
||||
"index_of",
|
||||
func(|(v, p): (&str, &str), _| Ok(OneOrNone(v.find(p).map(|v| v as isize)))),
|
||||
func(|(v, p): (&str, &str), _| {
|
||||
Ok(OneOrNone(v.find(p).map(|v| IntR::<0, INT_MAX>(v as isize))))
|
||||
}),
|
||||
)
|
||||
.add_var(
|
||||
"index_of_rev",
|
||||
func(|(v, p): (&str, &str), _| Ok(OneOrNone(v.rfind(p).map(|v| v as isize)))),
|
||||
func(|(v, p): (&str, &str), _| {
|
||||
Ok(OneOrNone(
|
||||
v.rfind(p).map(|v| IntR::<0, INT_MAX>(v as isize)),
|
||||
))
|
||||
}),
|
||||
)
|
||||
.add_var(
|
||||
"starts_with",
|
||||
@@ -92,31 +102,37 @@ impl Config {
|
||||
)
|
||||
.add_var(
|
||||
"substring",
|
||||
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(|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(String::new());
|
||||
}
|
||||
Ok(s[start..end].to_owned())
|
||||
}),
|
||||
func(
|
||||
|v: OneOf<
|
||||
(&str, IntR<INT_MIN, INT_MAX>),
|
||||
(&str, IntR<INT_MIN, INT_MAX>, IntR<INT_MIN, INT_MAX>),
|
||||
>,
|
||||
_| {
|
||||
let (s, start, end) = match v {
|
||||
OneOf::A((t, s)) => (t, s.0, None),
|
||||
OneOf::B((t, s, e)) => (t, s.0, Some(e.0)),
|
||||
};
|
||||
let start = if start < 0 {
|
||||
s.len().saturating_sub(start.abs() as usize)
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
let end = end
|
||||
.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(String::new());
|
||||
}
|
||||
Ok(s[start..end].to_owned())
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user