mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-11-04 13:21:26 +01:00 
			
		
		
		
	the math does math... at compile time, in types
This commit is contained in:
		
							parent
							
								
									c357e192a0
								
							
						
					
					
						commit
						754dd5df40
					
				@ -1,6 +1,6 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "mers"
 | 
			
		||||
version = "0.9.3"
 | 
			
		||||
version = "0.9.4"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
description = "dynamically typed but type-checked programming language"
 | 
			
		||||
@ -15,7 +15,7 @@ default = ["colored-output"]
 | 
			
		||||
colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
mers_lib = "0.9.3"
 | 
			
		||||
mers_lib = "0.9.4"
 | 
			
		||||
# mers_lib = { path = "../mers_lib" }
 | 
			
		||||
clap = { version = "4.3.19", features = ["derive"] }
 | 
			
		||||
colored = { version = "2.1.0", optional = true }
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "mers_lib"
 | 
			
		||||
version = "0.9.3"
 | 
			
		||||
version = "0.9.4"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
description = "library to use the mers language in other projects"
 | 
			
		||||
 | 
			
		||||
@ -51,13 +51,13 @@ impl Function {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn new_generic(
 | 
			
		||||
        out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
 | 
			
		||||
        out: impl Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync + 'static,
 | 
			
		||||
        run: impl Fn(Data, &mut Info) -> Result<Data, CheckError> + Send + Sync + 'static,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            info: 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, i| out(a, i))),
 | 
			
		||||
            run: Arc::new(run),
 | 
			
		||||
            inner_statements: None,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,43 @@ use crate::info::DisplayInfo;
 | 
			
		||||
 | 
			
		||||
use super::{MersData, MersType, Type};
 | 
			
		||||
 | 
			
		||||
/// The smallest representable integer.
 | 
			
		||||
/// Depends on the system for which mers is being compiled, as mers uses pointer-sized signed integers.
 | 
			
		||||
/// `-2^W`, `W` is the bit-width of a pointer on the system, often `32` or `64`.
 | 
			
		||||
pub const INT_MIN: isize = isize::MIN;
 | 
			
		||||
/// The largest representable integer.
 | 
			
		||||
/// Depends on the system for which mers is being compiled, as mers uses pointer-sized signed integers.
 | 
			
		||||
/// `2^W-1`, `W` is the bit-width of a pointer on the system, often `32` or `64`.
 | 
			
		||||
pub const INT_MAX: isize = isize::MAX;
 | 
			
		||||
/// The smallest integer representable by mers and by a signed 32-bit number.
 | 
			
		||||
/// `max(INT_MIN, -2^31)`
 | 
			
		||||
pub const INT32S_MIN: isize = if isize::BITS > i32::BITS {
 | 
			
		||||
    i32::MIN as isize
 | 
			
		||||
} else {
 | 
			
		||||
    isize::MIN
 | 
			
		||||
};
 | 
			
		||||
/// The largest integer representable by mers and by a signed 32-bit number.
 | 
			
		||||
/// `min(INT_MAX, 2^31-1)`
 | 
			
		||||
pub const INT32S_MAX: isize = if isize::BITS > i32::BITS {
 | 
			
		||||
    i32::MAX as isize
 | 
			
		||||
} else {
 | 
			
		||||
    isize::MAX
 | 
			
		||||
};
 | 
			
		||||
/// The smallest integer representable by mers and by an unsigned 32-bit number, assuming its value was negative.
 | 
			
		||||
/// `max(INT_MIN, -(2^32-1))`
 | 
			
		||||
pub const INT32U_MIN: isize = if isize::BITS > u32::BITS {
 | 
			
		||||
    -(u32::MAX as isize)
 | 
			
		||||
} else {
 | 
			
		||||
    isize::MIN
 | 
			
		||||
};
 | 
			
		||||
/// The largest integer representable by mers and by an unsigned 32-bit number.
 | 
			
		||||
/// `min(INT_MAX, 2^32-1)`
 | 
			
		||||
pub const INT32U_MAX: isize = if isize::BITS > u32::BITS {
 | 
			
		||||
    u32::MAX as isize
 | 
			
		||||
} else {
 | 
			
		||||
    isize::MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub struct Int(pub isize);
 | 
			
		||||
 | 
			
		||||
@ -22,7 +59,7 @@ impl MersData for Int {
 | 
			
		||||
        Box::new(Clone::clone(self))
 | 
			
		||||
    }
 | 
			
		||||
    fn as_type(&self) -> super::Type {
 | 
			
		||||
        Type::new(IntT)
 | 
			
		||||
        Type::new(IntT(self.0, self.0))
 | 
			
		||||
    }
 | 
			
		||||
    fn as_any(&self) -> &dyn Any {
 | 
			
		||||
        self
 | 
			
		||||
@ -35,8 +72,8 @@ impl MersData for Int {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct IntT;
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
pub struct IntT(pub isize, pub isize);
 | 
			
		||||
impl MersType for IntT {
 | 
			
		||||
    fn display(
 | 
			
		||||
        &self,
 | 
			
		||||
@ -46,13 +83,35 @@ impl MersType for IntT {
 | 
			
		||||
        write!(f, "{self}")
 | 
			
		||||
    }
 | 
			
		||||
    fn is_same_type_as(&self, other: &dyn MersType) -> bool {
 | 
			
		||||
        other.as_any().downcast_ref::<Self>().is_some()
 | 
			
		||||
        if let Some(other) = other.as_any().downcast_ref::<Self>() {
 | 
			
		||||
            self == other
 | 
			
		||||
        } else {
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn is_included_in(&self, target: &dyn MersType) -> bool {
 | 
			
		||||
        self.is_same_type_as(target)
 | 
			
		||||
        if let Some(target) = target.as_any().downcast_ref::<Self>() {
 | 
			
		||||
            target.0 <= self.0 && self.1 <= target.1
 | 
			
		||||
        } else {
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn subtypes(&self, acc: &mut Type) {
 | 
			
		||||
        acc.add(Arc::new(self.clone()));
 | 
			
		||||
        // INT_MIN .. INT32U_MIN .. INT32S_MIN .. 0 .. INT32S_MAX .. INT32U_MAX .. INT_MAX
 | 
			
		||||
        let mut add_range = |min, max| {
 | 
			
		||||
            // the range is non-empty, self starts before or where the range ends, and self ends after or where the range starts.
 | 
			
		||||
            if min <= max && self.0 <= max && self.1 >= min {
 | 
			
		||||
                acc.add(Arc::new(IntT(self.0.max(min), self.1.min(max))));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        add_range(INT_MIN, INT32U_MIN - 1);
 | 
			
		||||
        add_range(INT32U_MIN, INT32S_MIN - 1);
 | 
			
		||||
        add_range(INT32S_MIN, -1);
 | 
			
		||||
        add_range(0, 0);
 | 
			
		||||
        add_range(1, INT32S_MAX);
 | 
			
		||||
        add_range(INT32S_MAX + 1, INT32U_MAX);
 | 
			
		||||
        add_range(INT32U_MAX + 1, INT_MAX);
 | 
			
		||||
    }
 | 
			
		||||
    fn as_any(&self) -> &dyn Any {
 | 
			
		||||
        self
 | 
			
		||||
@ -72,6 +131,12 @@ impl Display for Int {
 | 
			
		||||
}
 | 
			
		||||
impl Display for IntT {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        write!(f, "Int")
 | 
			
		||||
        match (self.0, self.1) {
 | 
			
		||||
            (isize::MIN, isize::MAX) => write!(f, "Int"),
 | 
			
		||||
            (val, val2) if val == val2 => write!(f, "Int<{val}>"),
 | 
			
		||||
            (min, isize::MAX) => write!(f, "Int<{min}..>"),
 | 
			
		||||
            (isize::MIN, max) => write!(f, "Int<..{max}>"),
 | 
			
		||||
            (min, max) => write!(f, "Int<{min}..{max}>"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -413,6 +413,39 @@ impl Type {
 | 
			
		||||
        let n = new.as_any();
 | 
			
		||||
        if let Some(s) = n.downcast_ref::<Self>() {
 | 
			
		||||
            self.add_all(s);
 | 
			
		||||
        } else if let Some(n) = n.downcast_ref::<crate::data::int::IntT>() {
 | 
			
		||||
            let n = n.clone();
 | 
			
		||||
            let mut newt = None;
 | 
			
		||||
            for a in &self.types {
 | 
			
		||||
                if let Some(t) = a.as_any().downcast_ref::<crate::data::int::IntT>() {
 | 
			
		||||
                    if t.0 <= n.0 && n.1 <= t.1 {
 | 
			
		||||
                        // we are included in this type
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    if t.0 <= n.1.saturating_add(1) && n.0.saturating_sub(1) <= t.1 {
 | 
			
		||||
                        // this type will be added instead of the original `new`, and `t` will be removed from `self.types`.
 | 
			
		||||
                        newt = Some(crate::data::int::IntT(t.0.min(n.0), t.1.max(n.1)));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            let newt2 = newt.is_some();
 | 
			
		||||
            // remove types that are included in `self` before adding `self`
 | 
			
		||||
            let newt = newt.unwrap_or(n);
 | 
			
		||||
            let mut rmstack = vec![];
 | 
			
		||||
            for (i, a) in self.types.iter().enumerate() {
 | 
			
		||||
                if let Some(t) = a.as_any().downcast_ref::<crate::data::int::IntT>() {
 | 
			
		||||
                    if newt.0 <= t.0 && t.1 <= newt.1 {
 | 
			
		||||
                        rmstack.push(i);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            for i in rmstack.into_iter().rev() {
 | 
			
		||||
                self.types.remove(i);
 | 
			
		||||
            }
 | 
			
		||||
            if !newt2 {
 | 
			
		||||
                self.types.push(new);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if !self.types.iter().any(|t| new.is_included_in(t.as_ref())) {
 | 
			
		||||
                self.types.push(new);
 | 
			
		||||
 | 
			
		||||
@ -277,11 +277,11 @@ pub fn type_from_parsed(
 | 
			
		||||
                .find_map(|scope| scope.types.iter().find(|v| v.0 == name).map(|(_, v)| v))
 | 
			
		||||
            {
 | 
			
		||||
                Some(Ok(t)) => as_type.add_all(&*t),
 | 
			
		||||
                Some(Err(_)) => {
 | 
			
		||||
                    return Err(CheckError::new().msg_str(format!(
 | 
			
		||||
                        "Type: specified type without info, but type needs additional info"
 | 
			
		||||
                    )))
 | 
			
		||||
                }
 | 
			
		||||
                Some(Err(f)) => as_type.add_all(&*f("", info).map_err(|e| {
 | 
			
		||||
                    e.msg_str(format!(
 | 
			
		||||
                        "Note: specified type `{name}` without info, but type needs additional info: `{name}<...>`"
 | 
			
		||||
                    ))
 | 
			
		||||
                })?),
 | 
			
		||||
                None => return Err(CheckError::new().msg_str(format!("Unknown type '{name}'"))),
 | 
			
		||||
            },
 | 
			
		||||
            ParsedType::TypeWithInfo(name, additional_info) => match info
 | 
			
		||||
 | 
			
		||||
@ -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,10 +102,15 @@ impl Config {
 | 
			
		||||
            )
 | 
			
		||||
            .add_var(
 | 
			
		||||
                "substring",
 | 
			
		||||
                func(|v: OneOf<(&str, isize), (&str, isize, isize)>, _| {
 | 
			
		||||
                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, None),
 | 
			
		||||
                        OneOf::B((t, s, e)) => (t, s, Some(e)),
 | 
			
		||||
                            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)
 | 
			
		||||
@ -116,7 +131,8 @@ impl Config {
 | 
			
		||||
                            return Ok(String::new());
 | 
			
		||||
                        }
 | 
			
		||||
                        Ok(s[start..end].to_owned())
 | 
			
		||||
                }),
 | 
			
		||||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,8 +15,8 @@ fn variable() -> Res {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            run_code(Config::new(), format!("x := {n}, x"))?,
 | 
			
		||||
            TypedData(
 | 
			
		||||
                Type::new(data::int::IntT),
 | 
			
		||||
                Data::new(data::int::Int(n as _)),
 | 
			
		||||
                Type::new(data::int::IntT(n, n)),
 | 
			
		||||
                Data::new(data::int::Int(n)),
 | 
			
		||||
                mers_lib::info::Info::neverused(),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
@ -27,9 +27,9 @@ fn variable() -> Res {
 | 
			
		||||
#[test]
 | 
			
		||||
fn mutating_a_variable() -> Res {
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        run_code(Config::new(), "x := 5, &x = 2, x")?,
 | 
			
		||||
        run_code(Config::new(), "x := [Int<2..5>] 5, &x = 2, x")?,
 | 
			
		||||
        TypedData(
 | 
			
		||||
            Type::new(data::int::IntT),
 | 
			
		||||
            Type::new(data::int::IntT(2, 5)),
 | 
			
		||||
            Data::new(data::int::Int(2)),
 | 
			
		||||
            mers_lib::info::Info::neverused()
 | 
			
		||||
        ),
 | 
			
		||||
@ -40,9 +40,9 @@ fn mutating_a_variable() -> Res {
 | 
			
		||||
#[test]
 | 
			
		||||
fn variable_shadowing() -> Res {
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        run_code(Config::new(), "x := 5, { x := 2, &x = 3 }, x")?,
 | 
			
		||||
        run_code(Config::new(), "x := 5, { x := 2, &x = 2 }, x")?,
 | 
			
		||||
        TypedData(
 | 
			
		||||
            Type::new(data::int::IntT),
 | 
			
		||||
            Type::new(data::int::IntT(5, 5)),
 | 
			
		||||
            Data::new(data::int::Int(5)),
 | 
			
		||||
            mers_lib::info::Info::neverused()
 | 
			
		||||
        )
 | 
			
		||||
@ -55,7 +55,7 @@ fn identity_function() -> Res {
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        run_code(Config::new(), "id := x -> x, 4.id")?,
 | 
			
		||||
        TypedData(
 | 
			
		||||
            Type::new(data::int::IntT),
 | 
			
		||||
            Type::new(data::int::IntT(4, 4)),
 | 
			
		||||
            Data::new(data::int::Int(4)),
 | 
			
		||||
            mers_lib::info::Info::neverused()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user