diff --git a/src/ast/value.rs b/src/ast/value.rs index abbccd4..f23426b 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -18,6 +18,7 @@ pub enum Value { Int(i64), Float(f64), String(SmolStr), + Bool(bool) } impl Display for Value { @@ -26,6 +27,7 @@ impl Display for Value { Self::Int(int) => write!(f, "{}", int), Self::Float(float) => write!(f, "{}", float), Self::String(string) => write!(f, "{}", string), + Self::Bool(bool) => write!(f, "{}", bool) } } } @@ -78,6 +80,12 @@ impl From for Value { } } +impl From for Value{ + fn from(v: bool) -> Self { + Self::Bool(v) + } +} + impl Value { #[allow(clippy::wrong_self_convention)] pub fn to_expr(self, span: Span) -> Expr { diff --git a/src/ast/value/binop.rs b/src/ast/value/binop.rs index 4e3bfdc..1879d52 100644 --- a/src/ast/value/binop.rs +++ b/src/ast/value/binop.rs @@ -64,8 +64,20 @@ impl Value { Some(Value::Int(a / b)) } } - (Value::Float(a), Value::Float(b)) => Some(Value::Float(a / b)), - (Value::Int(a), Value::Float(b)) => Some(Value::Float(*a as f64 / b)), + (Value::Float(a), Value::Float(b)) => { + if *b == 0.0 { + None + } else { + Some(Value::Float(a / *b as f64)) + } + } + (Value::Int(a), Value::Float(b)) => { + if *b == 0.0 { + None + } else { + Some(Value::Float(*a as f64 / *b as f64)) + } + } (Value::Float(a), Value::Int(b)) => { if *b == 0 { None @@ -78,27 +90,81 @@ impl Value { } fn mod_(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => { + if *b == 0 { + None + } else { + Some(Value::Int(a % b)) + } + } + (Value::Float(a), Value::Float(b)) => { + if *b == 0.0 { + None + } else { + Some(Value::Float(a % b)) + } + } + (Value::Int(a), Value::Float(b)) => { + if *b == 0.0 { + None + } else { + Some(Value::Float(*a as f64 % b)) + } + } + (Value::Float(a), Value::Int(b)) => { + if *b == 0 { + None + } else { + Some(Value::Float(a % *b as f64)) + } + } + _ => None, + } } fn lt(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a < b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a < b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) < *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a < (*b as f64))), + _ => None, + } } fn gt(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a > b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a > b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) > *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a > (*b as f64))), + _ => None, + } } fn eq(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a == b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a == b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) == *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a == (*b as f64))), + _ => None, + } } fn and(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Bool(a), Value::Bool(b)) => Some(Value::Bool(*a && *b)), + _ => None, + } } fn or(&self, rhs: &Value) -> Option { - None + match (self, rhs) { + (Value::Bool(a), Value::Bool(b)) => Some(Value::Bool(*a || *b)), + _ => None, + } } fn join(&self, rhs: &Value) -> Option { @@ -117,19 +183,73 @@ impl Value { } fn le(&self, rhs: &Value) -> Option { - None + // Less than or equal to + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a <= b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a <= b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) <= *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a <= (*b as f64))), + _ => None, + } } fn ge(&self, rhs: &Value) -> Option { - None + // Greater than or equal to + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a >= b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a >= b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) >= *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a >= (*b as f64))), + _ => None, + } } fn ne(&self, rhs: &Value) -> Option { - None + // Not equal + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => Some(Value::Bool(a != b)), + (Value::Float(a), Value::Float(b)) => Some(Value::Bool(a != b)), + (Value::Int(a), Value::Float(b)) => Some(Value::Bool((*a as f64) != *b)), + (Value::Float(a), Value::Int(b)) => Some(Value::Bool(*a != (*b as f64))), + (Value::Bool(a), Value::Bool(b)) => Some(Value::Bool(a != b)), + (Value::String(a), Value::String(b)) => Some(Value::Bool(a != b)), + _ => None, + } } fn floor_div(&self, rhs: &Value) -> Option { - None + // Floor division (integer division) + match (self, rhs) { + (Value::Int(a), Value::Int(b)) => { + if *b == 0 { + None // Division by zero + } else { + Some(Value::Int(a / b)) + } + } + (Value::Float(a), Value::Float(b)) => { + if *b == 0.0 { + None // Division by zero + } else { + Some(Value::Int((a / b).floor() as i64)) + } + } + (Value::Int(a), Value::Float(b)) => { + if *b == 0.0 { + None // Division by zero + } else { + Some(Value::Int(((*a as f64) / b).floor() as i64)) + } + } + (Value::Float(a), Value::Int(b)) => { + if *b == 0 { + None // Division by zero + } else { + Some(Value::Int((a / (*b as f64)).floor() as i64)) + } + } + _ => None, + } } } @@ -170,4 +290,182 @@ mod tests { Some(Value::from(-1.0)) ); } + + #[cfg(test)] + mod tests { + use super::*; + + #[test] + fn test_div() { + assert_eq!(Value::from(10).div(&Value::from(2)), Some(Value::from(5))); + assert_eq!( + Value::from(10.0).div(&Value::from(2.0)), + Some(Value::from(5.0)) + ); + assert_eq!( + Value::from(10).div(&Value::from(2.0)), + Some(Value::from(5.0)) + ); + assert_eq!( + Value::from(10.0).div(&Value::from(2)), + Some(Value::from(5.0)) + ); + assert_eq!(Value::from(10).div(&Value::from(0)), None); // Division by zero + assert_eq!(Value::from(10.0).div(&Value::from(0.0)), None); // Division by zero + } + + #[test] + fn test_lt() { + assert_eq!(Value::from(1).lt(&Value::from(2)), Some(Value::from(true))); + assert_eq!( + Value::from(1.0).lt(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1).lt(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1.0).lt(&Value::from(2)), + Some(Value::from(true)) + ); + assert_eq!(Value::from(2).lt(&Value::from(1)), Some(Value::from(false))); + } + + #[test] + fn test_gt() { + assert_eq!(Value::from(2).gt(&Value::from(1)), Some(Value::from(true))); + assert_eq!( + Value::from(2.0).gt(&Value::from(1.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(2).gt(&Value::from(1.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(2.0).gt(&Value::from(1)), + Some(Value::from(true)) + ); + assert_eq!(Value::from(1).gt(&Value::from(2)), Some(Value::from(false))); + } + + #[test] + fn test_and() { + assert_eq!( + Value::from(true).and(&Value::from(true)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(true).and(&Value::from(false)), + Some(Value::from(false)) + ); + assert_eq!( + Value::from(false).and(&Value::from(true)), + Some(Value::from(false)) + ); + assert_eq!( + Value::from(false).and(&Value::from(false)), + Some(Value::from(false)) + ); + assert_eq!(Value::from(1).and(&Value::from(true)), None); // Invalid types + } + + #[test] + fn test_or() { + assert_eq!( + Value::from(true).or(&Value::from(true)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(true).or(&Value::from(false)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(false).or(&Value::from(true)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(false).or(&Value::from(false)), + Some(Value::from(false)) + ); + assert_eq!(Value::from(1).or(&Value::from(true)), None); // Invalid types + } + + #[test] + fn test_le() { + assert_eq!(Value::from(1).le(&Value::from(2)), Some(Value::from(true))); + assert_eq!( + Value::from(1.0).le(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1).le(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1.0).le(&Value::from(2)), + Some(Value::from(true)) + ); + assert_eq!(Value::from(2).le(&Value::from(1)), Some(Value::from(false))); + } + + #[test] + fn test_ge() { + assert_eq!(Value::from(2).ge(&Value::from(1)), Some(Value::from(true))); + assert_eq!( + Value::from(2.0).ge(&Value::from(1.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(2).ge(&Value::from(1.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(2.0).ge(&Value::from(1)), + Some(Value::from(true)) + ); + assert_eq!(Value::from(1).ge(&Value::from(2)), Some(Value::from(false))); + } + + #[test] + fn test_ne() { + assert_eq!(Value::from(1).ne(&Value::from(2)), Some(Value::from(true))); + assert_eq!( + Value::from(1.0).ne(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1).ne(&Value::from(2.0)), + Some(Value::from(true)) + ); + assert_eq!( + Value::from(1.0).ne(&Value::from(2)), + Some(Value::from(true)) + ); + assert_eq!(Value::from(1).ne(&Value::from(1)), Some(Value::from(false))); + } + + #[test] + fn test_floor_div() { + assert_eq!( + Value::from(10).floor_div(&Value::from(3)), + Some(Value::from(3)) + ); + assert_eq!( + Value::from(10.0).floor_div(&Value::from(3.0)), + Some(Value::from(3)) + ); + assert_eq!( + Value::from(10).floor_div(&Value::from(3.0)), + Some(Value::from(3)) + ); + assert_eq!( + Value::from(10.0).floor_div(&Value::from(3)), + Some(Value::from(3)) + ); + assert_eq!(Value::from(10).floor_div(&Value::from(0)), None); // Division by zero + assert_eq!(Value::from(10.0).floor_div(&Value::from(0.0)), None); // Division by zero + } + } } diff --git a/src/ast/value/unop.rs b/src/ast/value/unop.rs index 88c6bd6..2ac79f6 100644 --- a/src/ast/value/unop.rs +++ b/src/ast/value/unop.rs @@ -30,6 +30,7 @@ impl Value { Self::Int(integer) => Some(integer.to_string().len().into()), Self::Float(float) => Some(float.to_string().len().into()), Self::String(string) => Some(string.len().into()), + Self::Bool(bool) => None } } diff --git a/src/codegen/input.rs b/src/codegen/input.rs index 5bb7a12..9ba1f26 100644 --- a/src/codegen/input.rs +++ b/src/codegen/input.rs @@ -119,6 +119,9 @@ where T: Write + Seek write!(self, "[1,[10,{}]]", json!(**string_value)) } } + Value::Bool(bool_value) => { + write!(self, "[1,[4,{}]]", json!(bool_value)) + } } }