diff --git a/src/lib.rs b/src/lib.rs index d0166ee..6f90b4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,13 @@ mod test { assert_eq!(eval("7/(7/(7/(7/(7/(7)))))"), Ok(Value::Int(1))); } + #[test] + fn test_mod_examples() { + assert_eq!(eval("1 % 4"), Ok(Value::Int(1))); + assert_eq!(eval("6 % 4"), Ok(Value::Int(2))); + assert_eq!(eval("1 % 4 + 2"), Ok(Value::Int(3))); + } + #[test] fn test_type_errors() { assert_eq!( diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 350c153..a029e95 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -21,12 +21,14 @@ pub trait Operator { } pub struct RootNode; +pub struct Braced; + pub struct Add; pub struct Sub; pub struct Neg; pub struct Mul; pub struct Div; -pub struct Braced; +pub struct Mod; pub struct Const { value: Value, @@ -50,15 +52,16 @@ impl Identifier { impl Operator for RootNode { fn precedence(&self) -> i32 { - i32::min_value() + 200 } fn argument_amount(&self) -> usize { 1 } - fn eval(&self, _arguments: &[Value], _configuration: &Configuration) -> Result { - Err(Error::EvaluatedRootNode) + fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 1)?; + Ok(arguments[0].clone()) } } @@ -187,6 +190,32 @@ impl Operator for Div { } } +impl Operator for Mod { + fn precedence(&self) -> i32 { + 100 + } + + fn argument_amount(&self) -> usize { + 2 + } + + fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 2)?; + expect_number(&arguments[0])?; + expect_number(&arguments[1])?; + + if arguments[0].is_int() && arguments[1].is_int() { + Ok(Value::Int( + arguments[0].as_int().unwrap() % arguments[1].as_int().unwrap(), + )) + } else { + Ok(Value::Float( + arguments[0].as_float().unwrap() % arguments[1].as_float().unwrap(), + )) + } + } +} + impl Operator for Const { fn precedence(&self) -> i32 { 200 @@ -218,18 +247,3 @@ impl Operator for Identifier { configuration.get_value(&self.identifier) } } - -impl Operator for Braced { - fn precedence(&self) -> i32 { - 200 - } - - fn argument_amount(&self) -> usize { - 1 - } - - fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { - expect_argument_amount(arguments.len(), 1)?; - Ok(arguments[0].clone()) - } -} diff --git a/src/token/mod.rs b/src/token/mod.rs index 7605e85..ee344eb 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -7,6 +7,7 @@ pub enum Token { Minus, Star, Slash, + Percent, LBrace, RBrace, Whitespace, @@ -30,6 +31,7 @@ fn char_to_token(c: char) -> PartialToken { '-' => PartialToken::Token(Token::Minus), '*' => PartialToken::Token(Token::Star), '/' => PartialToken::Token(Token::Slash), + '%' => PartialToken::Token(Token::Percent), '(' => PartialToken::Token(Token::LBrace), ')' => PartialToken::Token(Token::RBrace), c => { @@ -50,6 +52,7 @@ impl Token { Token::Minus => false, Token::Star => false, Token::Slash => false, + Token::Percent => false, Token::LBrace => false, Token::RBrace => true, Token::Whitespace => false, diff --git a/src/tree/mod.rs b/src/tree/mod.rs index e10e230..c42c1b5 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -17,10 +17,6 @@ impl Node { fn root_node() -> Self { Self::new(RootNode) } - - fn braced_node() -> Self { - Self::new(Braced) - } pub fn eval(&self, configuration: &Configuration) -> Result { let mut arguments = Vec::new(); @@ -91,8 +87,9 @@ pub fn tokens_to_operator_tree(tokens: Vec) -> Result { } Token::Star => Some(Node::new(Mul)), Token::Slash => Some(Node::new(Div)), + Token::Percent => Some(Node::new(Mod)), Token::LBrace => { - root.push(Node::braced_node()); + root.push(Node::root_node()); None }, Token::RBrace => {