diff --git a/src/commands/eval/executor.rs b/src/commands/eval/executor.rs index 1e0a0ea..6467d03 100644 --- a/src/commands/eval/executor.rs +++ b/src/commands/eval/executor.rs @@ -90,6 +90,13 @@ impl>> Executor { (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x.powf(y))), _ => Err(RuntimeError::NoOverloadForTypes), }, + ParseTree::Mod(x, y) => match (self.exec(*x, locals, in_function)?, self.exec(*y, locals, in_function)?) { + (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x % y)), + (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x % y as f64)), + (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 % y)), + (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x % y)), + _ => Err(RuntimeError::NoOverloadForTypes), + }, ParseTree::EqualTo(x, y) => match (self.exec(*x, locals, in_function)?, self.exec(*y, locals, in_function)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x == y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 == y)), @@ -257,3 +264,11 @@ impl>> Iterator for Executor } } } + +#[cfg(test)] +mod tests { + #[test] + fn recursion() { + let program = ": countdown i ?? <= i i 0 countdown - i 1"; + } +} \ No newline at end of file diff --git a/src/commands/eval/parser.rs b/src/commands/eval/parser.rs index 385eb8e..efa2b76 100644 --- a/src/commands/eval/parser.rs +++ b/src/commands/eval/parser.rs @@ -41,6 +41,7 @@ pub enum ParseTree { Mul(Box, Box), Div(Box, Box), Exp(Box, Box), + Mod(Box, Box), // Boolean Operations EqualTo(Box, Box), @@ -118,6 +119,10 @@ impl ParseTree { Box::new(ParseTree::parse(tokens, globals, locals)?), Box::new(ParseTree::parse(tokens, globals, locals)?) )), + Op::Mod => Ok(ParseTree::Mod( + Box::new(ParseTree::parse(tokens, globals, locals)?), + Box::new(ParseTree::parse(tokens, globals, locals)?) + )), Op::Equ | Op::LazyEqu | Op::GlobalEqu | Op::LazyGlobalEqu => { let token = tokens.next() .ok_or(ParseError::UnexpectedEndInput)? diff --git a/src/commands/eval/tokenizer.rs b/src/commands/eval/tokenizer.rs index 28c1a21..20fe8a8 100644 --- a/src/commands/eval/tokenizer.rs +++ b/src/commands/eval/tokenizer.rs @@ -40,6 +40,7 @@ pub enum Op { Div, Exp, Equ, + Mod, LazyEqu, GlobalEqu, LazyGlobalEqu, @@ -90,8 +91,9 @@ impl Token { "+" => Ok(Token::Operator(Op::Add)), "-" => Ok(Token::Operator(Op::Sub)), "*" => Ok(Token::Operator(Op::Mul)), - "**" => Ok(Token::Operator(Op::Exp)), "/" => Ok(Token::Operator(Op::Div)), + "**" => Ok(Token::Operator(Op::Exp)), + "%" => Ok(Token::Operator(Op::Mod)), "=" => Ok(Token::Operator(Op::Equ)), "." => Ok(Token::Operator(Op::LazyEqu)), "=>" => Ok(Token::Operator(Op::GlobalEqu)), @@ -170,8 +172,8 @@ impl std::iter::Iterator for Tokenizer { let mut input = String::new(); match self.reader.read_to_string(&mut input) { - Ok(0) => return None, - Err(e) => return Some(Err(TokenizeError::IO(e))), + Ok(0) => None, + Err(e) => Some(Err(TokenizeError::IO(e))), _ => { let re = regex::Regex::new(r#"[a-zA-Z0-9\.'_]+|[`~!@#\$%\^&\*\(\)\+-=\[\]\{\}\\|;:,<\.>/\?]+|("[^"]+")"#).expect("This wont fail promise :3");