Merge pull request #54 from rustysec/power_of

i64 and f64 exponent implementation
This commit is contained in:
Lukáš Hozda [magnusi] 2017-11-24 10:16:13 +01:00 committed by GitHub
commit ecf143b649
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 8 deletions

View File

@ -1418,6 +1418,9 @@ impl Engine {
fn left_shift<T: Shl<T>>(x: T, y: T) -> <T as Shl<T>>::Output { x.shl(y) } fn left_shift<T: Shl<T>>(x: T, y: T) -> <T as Shl<T>>::Output { x.shl(y) }
fn right_shift<T: Shr<T>>(x: T, y: T) -> <T as Shr<T>>::Output { x.shr(y) } fn right_shift<T: Shr<T>>(x: T, y: T) -> <T as Shr<T>>::Output { x.shr(y) }
fn modulo<T: Rem<T>>(x: T, y: T) -> <T as Rem<T>>::Output { x % y} fn modulo<T: Rem<T>>(x: T, y: T) -> <T as Rem<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, "+", add, i32, i64, u32, u64, f32, f64);
reg_op!(engine, "-", sub, 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, "<<", left_shift, i32, i64, u32, u64);
reg_op!(engine, ">>", right_shift, i32, i64, u32, u64); reg_op!(engine, ">>", right_shift, i32, i64, u32, u64);
reg_op!(engine, "%", modulo, 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, "-", neg, i32, i64, f32, f64);
reg_un!(engine, "!", not, bool); reg_un!(engine, "!", not, bool);

View File

@ -46,8 +46,8 @@ mod engine;
mod fn_register; mod fn_register;
mod parser; mod parser;
//#[cfg(test)] #[cfg(test)]
//mod tests; mod tests;
pub use engine::{Engine, Scope, EvalAltResult}; pub use engine::{Engine, Scope, EvalAltResult};
pub use fn_register::FnRegister; pub use fn_register::FnRegister;

View File

@ -170,6 +170,8 @@ pub enum Token {
XOr, XOr,
Modulo, Modulo,
ModuloEquals, ModuloEquals,
PowerOf,
PowerOfEquals,
LexErr(LexError), LexErr(LexError),
} }
@ -223,7 +225,9 @@ impl Token {
XOr | XOr |
Modulo | Modulo |
ModuloEquals | ModuloEquals |
Return => true, Return |
PowerOf |
PowerOfEquals => true,
_ => false, _ => false,
} }
} }
@ -252,7 +256,8 @@ impl Token {
Pipe | Pipe |
Or | Or |
Ampersand | Ampersand |
And => true, And |
PowerOf => true,
_ => false, _ => false,
} }
} }
@ -701,7 +706,16 @@ impl<'a> TokenIterator<'a> {
} }
_ => return Some(Token::Modulo) _ => 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() => (), _x if _x.is_whitespace() => (),
_ => return Some(Token::LexErr(LexError::UnexpectedChar)), _ => return Some(Token::LexErr(LexError::UnexpectedChar)),
} }
@ -740,7 +754,8 @@ fn get_precedence(token: &Token) -> i32 {
| Token::AndEquals | Token::AndEquals
| Token::OrEquals | Token::OrEquals
| Token::XOrEquals | Token::XOrEquals
| Token::ModuloEquals => 10, | Token::ModuloEquals
| Token::PowerOfEquals => 10,
Token::Or Token::Or
| Token::XOr | Token::XOr
| Token::Pipe => 11, | Token::Pipe => 11,
@ -755,7 +770,8 @@ fn get_precedence(token: &Token) -> i32 {
Token::Plus Token::Plus
| Token::Minus => 20, | Token::Minus => 20,
Token::Divide Token::Divide
| Token::Multiply => 40, | Token::Multiply
| Token::PowerOf => 40,
Token::LeftShift Token::LeftShift
| Token::RightShift => 50, | Token::RightShift => 50,
Token::Modulo => 60, Token::Modulo => 60,
@ -1033,7 +1049,15 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
Box::new(lhs_curr), Box::new(lhs_curr),
Box::new(Expr::FnCall("%".to_string(), vec![lhs_copy, rhs])) 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), _ => return Err(ParseError::UnknownOperator),
}; };
} }

View File

@ -17,6 +17,7 @@ mod mismatched_op;
mod not; mod not;
mod number_literals; mod number_literals;
mod ops; mod ops;
mod power_of;
mod string; mod string;
mod unary_after_binary; mod unary_after_binary;
mod unary_minus; mod unary_minus;

27
src/tests/power_of.rs Normal file
View File

@ -0,0 +1,27 @@
use engine::Engine;
#[test]
fn test_power_of() {
let mut engine = Engine::new();
assert_eq!(engine.eval::<i64>("2 ~ 3").unwrap(), 8);
assert_eq!(engine.eval::<i64>("(-2 ~ 3)").unwrap(), -8);
assert_eq!(engine.eval::<f64>("2.2 ~ 3.3").unwrap(), 13.489468760533386_f64);
assert_eq!(engine.eval::<f64>("2.0~-2.0").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("(-2.0~-2.0)").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("(-2.0~-2)").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<i64>("4~3").unwrap(), 64);
}
#[test]
fn test_power_of_equals() {
let mut engine = Engine::new();
assert_eq!(engine.eval::<i64>("let x = 2; x ~= 3; x").unwrap(), 8);
assert_eq!(engine.eval::<i64>("let x = -2; x ~= 3; x").unwrap(), -8);
assert_eq!(engine.eval::<f64>("let x = 2.2; x ~= 3.3; x").unwrap(), 13.489468760533386_f64);
assert_eq!(engine.eval::<f64>("let x = 2.0; x ~= -2.0; x").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("let x = -2.0; x ~= -2.0; x").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<f64>("let x = -2.0; x ~= -2; x").unwrap(), 0.25_f64);
assert_eq!(engine.eval::<i64>("let x =4; x ~= 3; x").unwrap(), 64);
}