diff --git a/src/engine.rs b/src/engine.rs index 5428bb29..18aa0ce6 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1418,6 +1418,9 @@ impl Engine { fn left_shift>(x: T, y: T) -> >::Output { x.shl(y) } fn right_shift>(x: T, y: T) -> >::Output { x.shr(y) } fn modulo>(x: T, y: T) -> >::Output { x % y} + fn pow_i64_i64(x: i64, y: i64) -> i64 { x.pow(y as u32) } + fn pow_f64_f64(x: f64, y: f64) -> f64 { x.powf(y) } + fn pow_f64_i64(x: f64, y: i64) -> f64 { x.powi(y as i32) } reg_op!(engine, "+", add, i32, i64, u32, u64, f32, f64); reg_op!(engine, "-", sub, i32, i64, u32, u64, f32, f64); @@ -1441,6 +1444,9 @@ impl Engine { reg_op!(engine, "<<", left_shift, i32, i64, u32, u64); reg_op!(engine, ">>", right_shift, i32, i64, u32, u64); reg_op!(engine, "%", modulo, i32, i64, u32, u64); + engine.register_fn("~", pow_i64_i64); + engine.register_fn("~", pow_f64_f64); + engine.register_fn("~", pow_f64_i64); reg_un!(engine, "-", neg, i32, i64, f32, f64); reg_un!(engine, "!", not, bool); diff --git a/src/lib.rs b/src/lib.rs index 895a8bd4..03ba0945 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,8 +46,8 @@ mod engine; mod fn_register; mod parser; -//#[cfg(test)] -//mod tests; +#[cfg(test)] +mod tests; pub use engine::{Engine, Scope, EvalAltResult}; pub use fn_register::FnRegister; diff --git a/src/parser.rs b/src/parser.rs index 01d0f6ea..f3bcd15c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -170,6 +170,8 @@ pub enum Token { XOr, Modulo, ModuloEquals, + PowerOf, + PowerOfEquals, LexErr(LexError), } @@ -223,7 +225,9 @@ impl Token { XOr | Modulo | ModuloEquals | - Return => true, + Return | + PowerOf | + PowerOfEquals => true, _ => false, } } @@ -252,7 +256,8 @@ impl Token { Pipe | Or | Ampersand | - And => true, + And | + PowerOf => true, _ => false, } } @@ -701,7 +706,16 @@ impl<'a> TokenIterator<'a> { } _ => return Some(Token::Modulo) } - } + }, + '~' => { + match self.char_stream.peek() { + Some(&'=') => { + self.char_stream.next(); + return Some(Token::PowerOfEquals); + } + _ => return Some(Token::PowerOf) + } + }, _x if _x.is_whitespace() => (), _ => return Some(Token::LexErr(LexError::UnexpectedChar)), } @@ -740,7 +754,8 @@ fn get_precedence(token: &Token) -> i32 { | Token::AndEquals | Token::OrEquals | Token::XOrEquals - | Token::ModuloEquals => 10, + | Token::ModuloEquals + | Token::PowerOfEquals => 10, Token::Or | Token::XOr | Token::Pipe => 11, @@ -755,7 +770,8 @@ fn get_precedence(token: &Token) -> i32 { Token::Plus | Token::Minus => 20, Token::Divide - | Token::Multiply => 40, + | Token::Multiply + | Token::PowerOf => 40, Token::LeftShift | Token::RightShift => 50, Token::Modulo => 60, @@ -1033,7 +1049,15 @@ fn parse_binop<'a>(input: &mut Peekable>, Box::new(lhs_curr), Box::new(Expr::FnCall("%".to_string(), vec![lhs_copy, rhs])) ) - } + }, + Token::PowerOf => Expr::FnCall("~".to_string(), vec![lhs_curr, rhs]), + Token::PowerOfEquals => { + let lhs_copy = lhs_curr.clone(); + Expr::Assignment( + Box::new(lhs_curr), + Box::new(Expr::FnCall("~".to_string(), vec![lhs_copy, rhs])) + ) + }, _ => return Err(ParseError::UnknownOperator), }; } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index c48ea44b..1cb35a66 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -17,6 +17,7 @@ mod mismatched_op; mod not; mod number_literals; mod ops; +mod power_of; mod string; mod unary_after_binary; mod unary_minus; diff --git a/src/tests/power_of.rs b/src/tests/power_of.rs new file mode 100644 index 00000000..ed0b7800 --- /dev/null +++ b/src/tests/power_of.rs @@ -0,0 +1,27 @@ +use engine::Engine; + +#[test] +fn test_power_of() { + let mut engine = Engine::new(); + + assert_eq!(engine.eval::("2 ~ 3").unwrap(), 8); + assert_eq!(engine.eval::("(-2 ~ 3)").unwrap(), -8); + assert_eq!(engine.eval::("2.2 ~ 3.3").unwrap(), 13.489468760533386_f64); + assert_eq!(engine.eval::("2.0~-2.0").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("(-2.0~-2.0)").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("(-2.0~-2)").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("4~3").unwrap(), 64); +} + +#[test] +fn test_power_of_equals() { + let mut engine = Engine::new(); + + assert_eq!(engine.eval::("let x = 2; x ~= 3; x").unwrap(), 8); + assert_eq!(engine.eval::("let x = -2; x ~= 3; x").unwrap(), -8); + assert_eq!(engine.eval::("let x = 2.2; x ~= 3.3; x").unwrap(), 13.489468760533386_f64); + assert_eq!(engine.eval::("let x = 2.0; x ~= -2.0; x").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("let x = -2.0; x ~= -2.0; x").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("let x = -2.0; x ~= -2; x").unwrap(), 0.25_f64); + assert_eq!(engine.eval::("let x =4; x ~= 3; x").unwrap(), 64); +}