diff --git a/crates/erg_compiler/lib/core/_erg_ratio.py b/crates/erg_compiler/lib/core/_erg_ratio.py index aedeb8040..2624f1fa5 100644 --- a/crates/erg_compiler/lib/core/_erg_ratio.py +++ b/crates/erg_compiler/lib/core/_erg_ratio.py @@ -5,6 +5,7 @@ from _erg_type import MutType from _erg_float import FloatMut + class Ratio(Fraction): FRAC_ZERO = Fraction(0) @@ -24,7 +25,7 @@ def __new__(cls, fraction): def try_new(numerator: int, denominator: int): if isinstance(numerator, int) and isinstance(denominator, int): - return Ratio(numerator, denominator) + return Ratio((numerator, denominator)) else: return Error("not an integer") @@ -82,6 +83,7 @@ def __neg__(self): def __float__(self): return super().__float__() + class RatioMut(MutType): value: Ratio diff --git a/crates/erg_compiler/ty/value.rs b/crates/erg_compiler/ty/value.rs index 20135dac7..e16bc9d1a 100644 --- a/crates/erg_compiler/ty/value.rs +++ b/crates/erg_compiler/ty/value.rs @@ -909,6 +909,7 @@ impl TryFrom<&ValueObj> for usize { match val { ValueObj::Int(i) => usize::try_from(*i).map_err(|_| ()), ValueObj::Nat(n) => usize::try_from(*n).map_err(|_| ()), + ValueObj::Ratio(r) => usize::try_from(r.to_int()).map_err(|_| ()), ValueObj::Float(f) => Ok(*f as usize), ValueObj::Bool(b) => Ok(if *b { 1 } else { 0 }), _ => Err(()), @@ -1003,14 +1004,27 @@ impl ValueObj { pub const fn is_num(&self) -> bool { matches!( self, - Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) | Self::Inf | Self::NegInf + Self::Float(_) + | Self::Ratio(_) + | Self::Int(_) + | Self::Nat(_) + | Self::Bool(_) + | Self::Inf + | Self::NegInf ) } pub const fn is_float(&self) -> bool { matches!( self, - Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) + Self::Float(_) | Self::Ratio(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) + ) + } + + pub const fn is_ratio(&self) -> bool { + matches!( + self, + Self::Ratio(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) ) } @@ -1436,32 +1450,22 @@ impl ValueObj { pub fn try_div(self, other: Self) -> Option { match (self, other) { - (Self::Nat(l), Self::Nat(r)) => Some(Self::Ratio( - Ratio::new(l as i64, 1) / Ratio::new(r as i64, 1), - )), - (Self::Nat(l), Self::Int(r)) => Some(Self::Ratio( - Ratio::new(l as i64, 1) / Ratio::new(r as i64, 1), - )), + (Self::Nat(l), Self::Nat(r)) => Some(Self::Ratio(Ratio::new(l as i64, r as i64))), + (Self::Nat(l), Self::Int(r)) => Some(Self::Ratio(Ratio::new(l as i64, r as i64))), (Self::Nat(l), Self::Ratio(r)) => Some(Self::Ratio(Ratio::new(l as i64, 1) / r)), - (Self::Nat(l), Self::Float(r)) => { - Some(Self::Ratio(Ratio::new(l as i64, 1) / Ratio::float_new(r))) - } + (Self::Nat(l), Self::Float(r)) => Some(Self::Float(l as f64 / r)), (Self::Int(l), Self::Nat(r)) => Some(Self::Ratio( Ratio::new(l as i64, 1) / Ratio::new(r as i64, 1), )), - (Self::Int(l), Self::Int(r)) => Some(Self::Ratio( - Ratio::new(l as i64, 1) / Ratio::new(r as i64, 1), - )), + (Self::Int(l), Self::Int(r)) => Some(Self::Ratio(Ratio::new(l as i64, r as i64))), (Self::Int(l), Self::Ratio(r)) => Some(Self::Ratio(Ratio::new(l as i64, 1) / r)), - (Self::Int(l), Self::Float(r)) => { - Some(Self::Ratio(Ratio::new(l as i64, 1) / Ratio::float_new(r))) - } + (Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 / r)), (Self::Ratio(l), Self::Nat(r)) => Some(Self::Ratio(l / Ratio::new(r as i64, 1))), (Self::Ratio(l), Self::Int(r)) => Some(Self::Ratio(l / Ratio::new(r as i64, 1))), (Self::Ratio(l), Self::Ratio(r)) => Some(Self::Ratio(l / r)), (Self::Ratio(l), Self::Float(r)) => Some(Self::Float(l.to_float() / r)), (Self::Float(l), Self::Nat(r)) => Some(Self::Float(l / r as f64)), - (Self::Float(l), Self::Int(r)) => Some(Self::from(l / r as f64)), + (Self::Float(l), Self::Int(r)) => Some(Self::Float(l / r as f64)), (Self::Float(l), Self::Ratio(r)) => Some(Self::Float(l / r.to_float())), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l / r)), // TODO: x/±Inf = 0 diff --git a/tests/eval/literal.rs b/tests/eval/literal.rs index dcbde94ad..a15d2feb7 100644 --- a/tests/eval/literal.rs +++ b/tests/eval/literal.rs @@ -156,5 +156,7 @@ fn eval_assert_inequality_2() { #[test] #[ignore] fn eval_ratio() { - assert_eq!(eval("print! 0.1234"), successful_output("0.1234\n")); + assert_eq!(eval("print! 3/10"), successful_output("3/10\n")); + assert_eq!(eval("print! 2.3%2"), successful_output("3/10\n")); + assert_eq!(eval("print! 0.3"), successful_output("3/10\n")); } diff --git a/tests/should_ok/ratio.er b/tests/should_ok/ratio.er index 2a120ac9c..dbfb9b5a2 100644 --- a/tests/should_ok/ratio.er +++ b/tests/should_ok/ratio.er @@ -1,13 +1,14 @@ -r: Ratio = 7.5 +r: Ratio = 7.5 # 15/2 # basic operations -assert r == 15 / 2 -assert r + 1 == 17 / 2 -assert r - 1 == 13 / 2 +assert r == 15/2 +assert r + 1 == 17/2 +assert r - 1 == 13/2 assert r * 2 == 15 -assert r / 2 == 15 / 4 -assert r % 2 == 3 / 2 +assert r / 2 == 15/4 +assert r // 2 == 3 +assert r % 2 == 3/2 -r_zero: Ratio = 0.0 +r_zero: Ratio = 0.0 # 0/1 # zero operations assert r_zero + 1 == 1 assert r_zero - 1 == -1